unsigned long sysclk;
 
        struct pcm3168a_io_params io_params[2];
+       struct snd_soc_dai_driver dai_drv[2];
 };
 
 static const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" };
        return 0;
 }
 
+static void pcm3168a_update_fixup_pcm_stream(struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
+       u64 formats = SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE;
+       unsigned int channel_max = dai->id == PCM3168A_DAI_DAC ? 8 : 6;
+
+       if (!pcm3168a->io_params[dai->id].fmt)
+               return;
+
+       if (pcm3168a->io_params[dai->id].fmt == PCM3168A_FMT_RIGHT_J) {
+               /* S16_LE is only supported in RIGHT_J mode */
+               formats |= SNDRV_PCM_FMTBIT_S16_LE;
+
+               /*
+                * If multi DIN/DOUT is not selected, RIGHT_J can only support
+                * two channels (no TDM support)
+                */
+               if (pcm3168a->io_params[dai->id].tdm_slots != 2)
+                       channel_max = 2;
+       }
+
+       if (dai->id == PCM3168A_DAI_DAC) {
+               dai->driver->playback.channels_max = channel_max;
+               dai->driver->playback.formats = formats;
+       } else {
+               dai->driver->capture.channels_max = channel_max;
+               dai->driver->capture.formats = formats;
+       }
+}
+
 static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format)
 {
        struct snd_soc_component *component = dai->component;
 
        regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift);
 
+       pcm3168a_update_fixup_pcm_stream(dai);
+
        return 0;
 }
 
        else
                io_params->tdm_mask = rx_mask;
 
+       pcm3168a_update_fixup_pcm_stream(dai);
+
        return 0;
 }
 
        return 0;
 }
 
-static int pcm3168a_startup(struct snd_pcm_substream *substream,
-                           struct snd_soc_dai *dai)
-{
-       struct snd_soc_component *component = dai->component;
-       struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
-       unsigned int sample_min;
-       unsigned int channel_max;
-       unsigned int channel_maxs[] = {
-               8, /* DAC */
-               6  /* ADC */
-       };
-
-       /*
-        * Available Data Bits
-        *
-        * RIGHT_J : 24 / 16
-        * LEFT_J  : 24
-        * I2S     : 24
-        *
-        * TDM available
-        *
-        * I2S
-        * LEFT_J
-        */
-       switch (pcm3168a->io_params[dai->id].fmt) {
-       case PCM3168A_FMT_RIGHT_J:
-               sample_min  = 16;
-               channel_max =  2;
-               break;
-       case PCM3168A_FMT_LEFT_J:
-       case PCM3168A_FMT_I2S:
-       case PCM3168A_FMT_DSP_A:
-       case PCM3168A_FMT_DSP_B:
-               sample_min  = 24;
-               channel_max = channel_maxs[dai->id];
-               break;
-       default:
-               sample_min  = 24;
-               channel_max =  2;
-       }
-
-       snd_pcm_hw_constraint_minmax(substream->runtime,
-                                    SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
-                                    sample_min, 32);
-
-       /* Allow all channels in multi DIN/DOUT mode */
-       if (pcm3168a->io_params[dai->id].tdm_slots == 2)
-               channel_max = channel_maxs[dai->id];
-
-       snd_pcm_hw_constraint_minmax(substream->runtime,
-                                    SNDRV_PCM_HW_PARAM_CHANNELS,
-                                    2, channel_max);
-
-       return 0;
-}
 static const struct snd_soc_dai_ops pcm3168a_dai_ops = {
-       .startup        = pcm3168a_startup,
        .set_fmt        = pcm3168a_set_dai_fmt,
        .set_sysclk     = pcm3168a_set_dai_sysclk,
        .hw_params      = pcm3168a_hw_params,
        pm_runtime_enable(dev);
        pm_runtime_idle(dev);
 
-       ret = devm_snd_soc_register_component(dev, &pcm3168a_driver, pcm3168a_dais,
-                       ARRAY_SIZE(pcm3168a_dais));
+       memcpy(pcm3168a->dai_drv, pcm3168a_dais, sizeof(pcm3168a->dai_drv));
+       ret = devm_snd_soc_register_component(dev, &pcm3168a_driver,
+                                             pcm3168a->dai_drv,
+                                             ARRAY_SIZE(pcm3168a->dai_drv));
        if (ret) {
                dev_err(dev, "failed to register component: %d\n", ret);
                goto err_regulator;