diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index af7fce2b574d..198d37d04d78 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -977,6 +977,15 @@ int snd_interval_ratnum(struct snd_interval *i,
 void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params);
 void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var);
 
+int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params,
+				struct snd_pcm_hw_rule *rule);
+int snd_pcm_hw_rule_format(struct snd_pcm_hw_params *params,
+			   struct snd_pcm_hw_rule *rule);
+int snd_pcm_hw_rule_mul(struct snd_pcm_hw_params *params,
+			struct snd_pcm_hw_rule *rule);
+int snd_pcm_hw_rule_div(struct snd_pcm_hw_params *params,
+			struct snd_pcm_hw_rule *rule);
+
 int snd_pcm_hw_refine(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params);
 
 int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h
index e296a3949b18..c5825876824a 100644
--- a/include/sound/soc-dpcm.h
+++ b/include/sound/soc-dpcm.h
@@ -95,6 +95,7 @@ struct snd_soc_dpcm_runtime {
 	int users;
 	struct snd_pcm_runtime *runtime;
 	struct snd_pcm_hw_params hw_params;
+	struct snd_pcm_hw_constraints hw_constraints;
 
 	/* state and update */
 	enum snd_soc_dpcm_update runtime_update;
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 582144f99045..125fafdf7517 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -16,6 +16,7 @@
 #include <sound/info.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
+#include <sound/soc.h>
 #include <sound/timer.h>
 
 #include "pcm_local.h"
@@ -1121,12 +1122,19 @@ int snd_pcm_hw_rule_add(struct snd_pcm_substream *substream, unsigned int cond,
 			snd_pcm_hw_rule_func_t func, void *private,
 			int dep, ...)
 {
-	struct snd_pcm_hw_constraints *constrs =
-					&substream->runtime->hw_constraints;
+	struct snd_pcm_hw_constraints *constrs;
 	struct snd_pcm_hw_rule *c;
 	unsigned int k;
 	va_list args;
 
+	if (substream->pcm->internal) {
+		struct snd_soc_pcm_runtime *rtd = substream->private_data;
+		struct snd_soc_dpcm_runtime *dpcm = &rtd->dpcm[substream->stream];
+
+		constrs = &dpcm->hw_constraints;
+	} else {
+		constrs = &substream->runtime->hw_constraints;
+	}
 	va_start(args, dep);
 	if (constrs->rules_num >= constrs->rules_all) {
 		struct snd_pcm_hw_rule *new;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 5feeef1b43f1..d6f14162bce5 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -2278,23 +2278,25 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
 /*
  * hw configurator
  */
-static int snd_pcm_hw_rule_mul(struct snd_pcm_hw_params *params,
-			       struct snd_pcm_hw_rule *rule)
+int snd_pcm_hw_rule_mul(struct snd_pcm_hw_params *params,
+			struct snd_pcm_hw_rule *rule)
 {
 	struct snd_interval t;
 	snd_interval_mul(hw_param_interval_c(params, rule->deps[0]),
 		     hw_param_interval_c(params, rule->deps[1]), &t);
 	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
 }
+EXPORT_SYMBOL(snd_pcm_hw_rule_mul);
 
-static int snd_pcm_hw_rule_div(struct snd_pcm_hw_params *params,
-			       struct snd_pcm_hw_rule *rule)
+int snd_pcm_hw_rule_div(struct snd_pcm_hw_params *params,
+			struct snd_pcm_hw_rule *rule)
 {
 	struct snd_interval t;
 	snd_interval_div(hw_param_interval_c(params, rule->deps[0]),
 		     hw_param_interval_c(params, rule->deps[1]), &t);
 	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
 }
+EXPORT_SYMBOL(snd_pcm_hw_rule_div);
 
 static int snd_pcm_hw_rule_muldivk(struct snd_pcm_hw_params *params,
 				   struct snd_pcm_hw_rule *rule)
@@ -2316,8 +2318,8 @@ static int snd_pcm_hw_rule_mulkdiv(struct snd_pcm_hw_params *params,
 	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
 }
 
-static int snd_pcm_hw_rule_format(struct snd_pcm_hw_params *params,
-				  struct snd_pcm_hw_rule *rule)
+int snd_pcm_hw_rule_format(struct snd_pcm_hw_params *params,
+			   struct snd_pcm_hw_rule *rule)
 {
 	snd_pcm_format_t k;
 	const struct snd_interval *i =
@@ -2337,9 +2339,10 @@ static int snd_pcm_hw_rule_format(struct snd_pcm_hw_params *params,
 	}
 	return snd_mask_refine(mask, &m);
 }
+EXPORT_SYMBOL(snd_pcm_hw_rule_format);
 
-static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params,
-				       struct snd_pcm_hw_rule *rule)
+int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params,
+				struct snd_pcm_hw_rule *rule)
 {
 	struct snd_interval t;
 	snd_pcm_format_t k;
@@ -2363,6 +2366,7 @@ static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params,
 	t.integer = 1;
 	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
 }
+EXPORT_SYMBOL(snd_pcm_hw_rule_sample_bits);
 
 #if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12
 #error "Change this table"
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 65f8ea73bae7..dae246918e0d 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1471,6 +1471,43 @@ void dpcm_be_dai_stop(struct snd_soc_pcm_runtime *fe, int stream,
 	}
 }
 
+static int dpcm_hw_constraints_init(struct snd_pcm_substream *substream)
+{
+	int err;
+
+	if (!substream->pcm->internal)
+		return 0;
+
+	err = snd_pcm_hw_rule_add(substream, 0, SNDRV_PCM_HW_PARAM_FORMAT,
+				  snd_pcm_hw_rule_format, NULL,
+				  SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
+	if (err < 0)
+		return err;
+	err = snd_pcm_hw_rule_add(substream, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+				  snd_pcm_hw_rule_sample_bits, NULL,
+				  SNDRV_PCM_HW_PARAM_FORMAT,
+				  SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
+	if (err < 0)
+		return err;
+	err = snd_pcm_hw_rule_add(substream, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+				  snd_pcm_hw_rule_div, NULL,
+				  SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+	if (err < 0)
+		return err;
+	err = snd_pcm_hw_rule_add(substream, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS,
+				  snd_pcm_hw_rule_mul, NULL,
+				  SNDRV_PCM_HW_PARAM_SAMPLE_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+	if (err < 0)
+		return err;
+	err = snd_pcm_hw_rule_add(substream, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+				  snd_pcm_hw_rule_div, NULL,
+				  SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+				  -1);
+	if (err < 0)
+		return err;
+	return 0;
+}
+
 int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
 {
 	struct snd_soc_pcm_runtime *be;
@@ -1513,6 +1550,13 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
 			stream ? "capture" : "playback", be->dai_link->name);
 
 		be_substream->runtime = be->dpcm[stream].runtime;
+
+		/* initialize the BE constraints */
+		err = dpcm_hw_constraints_init(be_substream);
+		if (err < 0) {
+			dev_dbg(be->dev, "dpcm_hw_constraints_init failed\n");
+			goto unwind;
+		}
 		err = soc_pcm_open(be_substream);
 		if (err < 0) {
 			be->dpcm[stream].users--;
