flush_delayed_work(&rtd->delayed_work);
 }
 
-static void codec2codec_close_delayed_work(struct work_struct *work)
-{
-       /*
-        * Currently nothing to do for c2c links
-        * Since c2c links are internal nodes in the DAPM graph and
-        * don't interface with the outside world or application layer
-        * we don't have to do any special handling on close.
-        */
-}
-
 #ifdef CONFIG_PM_SLEEP
 /* powers down audio subsystem for suspend */
 int snd_soc_suspend(struct device *dev)
                return ret;
        }
 
-       if (!dai_link->params) {
-               /* create the pcm */
-               ret = soc_new_pcm(rtd, num);
-               if (ret < 0) {
-                       dev_err(card->dev, "ASoC: can't create pcm %s :%d\n",
-                               dai_link->stream_name, ret);
-                       return ret;
-               }
-               ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd);
-               if (ret < 0)
-                       return ret;
-               ret = soc_link_dai_pcm_new(rtd->codec_dais,
-                                          rtd->num_codecs, rtd);
-               if (ret < 0)
-                       return ret;
-       } else {
-               INIT_DELAYED_WORK(&rtd->delayed_work,
-                                 codec2codec_close_delayed_work);
+       /* create the pcm */
+       ret = soc_new_pcm(rtd, num);
+       if (ret < 0) {
+               dev_err(card->dev, "ASoC: can't create pcm %s :%d\n",
+                       dai_link->stream_name, ret);
+               return ret;
        }
-
-       return 0;
+       ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd);
+       if (ret < 0)
+               return ret;
+       ret = soc_link_dai_pcm_new(rtd->codec_dais,
+                                  rtd->num_codecs, rtd);
+       return ret;
 }
 
 static int soc_bind_aux_dev(struct snd_soc_card *card, int num)
 
        mutex_unlock(&rtd->pcm_mutex);
 }
 
+static void codec2codec_close_delayed_work(struct work_struct *work)
+{
+       /*
+        * Currently nothing to do for c2c links
+        * Since c2c links are internal nodes in the DAPM graph and
+        * don't interface with the outside world or application layer
+        * we don't have to do any special handling on close.
+        */
+}
+
 /*
  * Called by ALSA when a PCM substream is closed. Private data can be
  * freed here. The cpu DAI, codec DAI, machine and components are also
                playback = rtd->dai_link->dpcm_playback;
                capture = rtd->dai_link->dpcm_capture;
        } else {
+               /* Adapt stream for codec2codec links */
+               struct snd_soc_pcm_stream *cpu_capture = rtd->dai_link->params ?
+                       &cpu_dai->driver->playback : &cpu_dai->driver->capture;
+               struct snd_soc_pcm_stream *cpu_playback = rtd->dai_link->params ?
+                       &cpu_dai->driver->capture : &cpu_dai->driver->playback;
+
                for_each_rtd_codec_dai(rtd, i, codec_dai) {
                        if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
                            snd_soc_dai_stream_valid(cpu_dai,   SNDRV_PCM_STREAM_PLAYBACK))
                            snd_soc_dai_stream_valid(cpu_dai,   SNDRV_PCM_STREAM_CAPTURE))
                                capture = 1;
                }
+
+               capture = capture && cpu_capture->channels_min;
+               playback = playback && cpu_playback->channels_min;
        }
 
        if (rtd->dai_link->playback_only) {
        }
 
        /* create the PCM */
-       if (rtd->dai_link->no_pcm) {
+       if (rtd->dai_link->params) {
+               snprintf(new_name, sizeof(new_name), "codec2codec(%s)",
+                        rtd->dai_link->stream_name);
+
+               ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
+                                          playback, capture, &pcm);
+       } else if (rtd->dai_link->no_pcm) {
                snprintf(new_name, sizeof(new_name), "(%s)",
                        rtd->dai_link->stream_name);
 
        dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name);
 
        /* DAPM dai link stream work */
-       INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
+       if (rtd->dai_link->params)
+               INIT_DELAYED_WORK(&rtd->delayed_work,
+                                 codec2codec_close_delayed_work);
+       else
+               INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
 
        pcm->nonatomic = rtd->dai_link->nonatomic;
        rtd->pcm = pcm;
        pcm->private_data = rtd;
 
-       if (rtd->dai_link->no_pcm) {
+       if (rtd->dai_link->no_pcm || rtd->dai_link->params) {
                if (playback)
                        pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
                if (capture)