diff --git a/libavfilter/vf_scale_npp.c b/libavfilter/vf_scale_npp.c
index 8e9113521c..53e9e9c4a3 100644
--- a/libavfilter/vf_scale_npp.c
+++ b/libavfilter/vf_scale_npp.c
@@ -160,6 +160,7 @@ typedef struct NPPScaleContext {
     double var_values[VARS_NB];
 
     int eval_mode;
+    int force_reconfig;
 } NPPScaleContext;
 
 const FFFilter ff_vf_scale2ref_npp;
@@ -254,9 +255,10 @@ static int nppscale_parse_expr(AVFilterContext* ctx, char* str_expr,
     if (ret < 0)
         goto revert;
 
-    if (is_inited && (ret = config_props(ctx->outputs[0])) < 0)
-        goto revert;
-
+    if (is_inited) {
+        /* expression updated at runtime, reconfigure on next frame */
+        scale->force_reconfig = 1;
+    }
     av_expr_free(old_pexpr);
     old_pexpr = NULL;
     av_freep(&old_str_expr);
@@ -528,7 +530,13 @@ static int init_processing_chain(AVFilterContext *ctx, int in_width, int in_heig
     enum AVPixelFormat out_deinterleaved_format;
 
     int i, ret, last_stage = -1;
-
+    /* reset dynamic flags for reconfiguration */
+    s->passthrough = 0;
+    for (i = 0; i < FF_ARRAY_ELEMS(s->stages); i++) {
+        s->stages[i].stage_needed = 0;
+        s->stages[i].planes_out[0].width  = 0;
+        s->stages[i].planes_out[0].height = 0;
+    }
     /* check that we have a hw context */
     if (!inl->hw_frames_ctx) {
         av_log(ctx, AV_LOG_ERROR, "No hw context provided on input\n");
@@ -793,7 +801,7 @@ static int nppscale_scale(AVFilterLink *link, AVFrame *out, AVFrame *in)
                     in->sample_aspect_ratio.den != link->sample_aspect_ratio.den ||
                     in->sample_aspect_ratio.num != link->sample_aspect_ratio.num;
 
-    if (s->eval_mode == EVAL_MODE_FRAME || frame_changed) {
+    if (s->eval_mode == EVAL_MODE_FRAME || frame_changed || s->force_reconfig) {
         unsigned vars_w[VARS_NB] = { 0 }, vars_h[VARS_NB] = { 0 };
 
         av_expr_count_vars(s->w_pexpr, vars_w, VARS_NB);
@@ -801,10 +809,11 @@ static int nppscale_scale(AVFilterLink *link, AVFrame *out, AVFrame *in)
 
         if (s->eval_mode == EVAL_MODE_FRAME && !frame_changed && !IS_SCALE2REF(ctx) &&
             !(vars_w[VAR_N] || vars_w[VAR_T]) &&
-            !(vars_h[VAR_N] || vars_h[VAR_T]) && s->w && s->h)
+            !(vars_h[VAR_N] || vars_h[VAR_T]) && s->w && s->h &&
+            !s->force_reconfig)
             goto scale;
 
-        if (s->eval_mode == EVAL_MODE_INIT) {
+        if (s->eval_mode == EVAL_MODE_INIT && frame_changed && !s->force_reconfig) {
             snprintf(buf, sizeof(buf)-1, "%d", outlink->w);
             av_opt_set(s, "w", buf, 0);
             snprintf(buf, sizeof(buf)-1, "%d", outlink->h);
@@ -834,8 +843,11 @@ static int nppscale_scale(AVFilterLink *link, AVFrame *out, AVFrame *in)
         link->sample_aspect_ratio.den = in->sample_aspect_ratio.den;
         link->sample_aspect_ratio.num = in->sample_aspect_ratio.num;
 
-        if ((ret = config_props(outlink)) < 0)
+        ret = config_props(outlink);
+        if (ret < 0)
             return ret;
+
+        s->force_reconfig = 0;
     }
 
 scale:
@@ -951,6 +963,39 @@ static int nppscale_filter_frame_ref(AVFilterLink *link, AVFrame *in)
     return ff_filter_frame(outlink, in);
 }
 
+static int process_command(AVFilterContext *ctx,
+                           const char *cmd, const char *args,
+                           char *res, int res_len, int flags)
+{
+    NPPScaleContext *scale = ctx->priv;
+    char *str_expr;
+    AVExpr **pexpr_ptr;
+    const char *opt_name;
+    int ret;
+    int is_w = !strcmp(cmd, "width")  || !strcmp(cmd, "w");
+    int is_h = !strcmp(cmd, "height") || !strcmp(cmd, "h");
+
+    if (is_w) {
+        str_expr  = scale->w_expr;
+        pexpr_ptr = &scale->w_pexpr;
+        opt_name  = "w";
+    } else if (is_h) {
+        str_expr  = scale->h_expr;
+        pexpr_ptr = &scale->h_pexpr;
+        opt_name  = "h";
+    } else {
+        return AVERROR(ENOSYS);
+    }
+
+    ret = nppscale_parse_expr(ctx, str_expr, pexpr_ptr, opt_name, args);
+    if (ret < 0)
+        av_log(ctx, AV_LOG_ERROR,
+               "Failed to process command '%s'='%s'. Keeping old parameters.\n",
+               cmd, args ? args : "(null)");
+
+    return ret;
+}
+
 static int request_frame(AVFilterLink *outlink)
 {
     return ff_request_frame(outlink->src->inputs[0]);
@@ -963,9 +1008,10 @@ static int request_frame_ref(AVFilterLink *outlink)
 
 #define OFFSET(x) offsetof(NPPScaleContext, x)
 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM)
+#define TFLAGS (AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM)
 static const AVOption options[] = {
-    { "w",      "Output video width",  OFFSET(w_expr),     AV_OPT_TYPE_STRING, .flags = FLAGS },
-    { "h",      "Output video height", OFFSET(h_expr),     AV_OPT_TYPE_STRING, .flags = FLAGS },
+    { "w",      "Output video width",  OFFSET(w_expr),     AV_OPT_TYPE_STRING, .flags = TFLAGS },
+    { "h",      "Output video height", OFFSET(h_expr),     AV_OPT_TYPE_STRING, .flags = TFLAGS },
     { "format", "Output pixel format", OFFSET(format_str), AV_OPT_TYPE_STRING, { .str = "same" }, .flags = FLAGS },
     { "s",      "Output video size",   OFFSET(size_str),   AV_OPT_TYPE_STRING, { .str = NULL   }, .flags = FLAGS },
 
@@ -1030,6 +1076,8 @@ const FFFilter ff_vf_scale_npp = {
 
     FILTER_SINGLE_PIXFMT(AV_PIX_FMT_CUDA),
 
+    .process_command = process_command,
+
     .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
 };
 
