}
 EXPORT_SYMBOL_HDA(snd_hda_eld_proc_free);
 
+/* update PCM info based on ELD */
+void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm,
+                             struct hda_pcm_stream *codec_pars)
+{
+       int i;
+
+       pcm->rates = 0;
+       pcm->formats = 0;
+       pcm->maxbps = 0;
+       pcm->channels_min = -1;
+       pcm->channels_max = 0;
+       for (i = 0; i < eld->sad_count; i++) {
+               struct cea_sad *a = &eld->sad[i];
+               pcm->rates |= a->rates;
+               if (a->channels < pcm->channels_min)
+                       pcm->channels_min = a->channels;
+               if (a->channels > pcm->channels_max)
+                       pcm->channels_max = a->channels;
+               if (a->format == AUDIO_CODING_TYPE_LPCM) {
+                       if (a->sample_bits & AC_SUPPCM_BITS_16) {
+                               pcm->formats |= SNDRV_PCM_FMTBIT_S16_LE;
+                               if (pcm->maxbps < 16)
+                                       pcm->maxbps = 16;
+                       }
+                       if (a->sample_bits & AC_SUPPCM_BITS_20) {
+                               pcm->formats |= SNDRV_PCM_FMTBIT_S32_LE;
+                               if (pcm->maxbps < 20)
+                                       pcm->maxbps = 20;
+                       }
+                       if (a->sample_bits & AC_SUPPCM_BITS_24) {
+                               pcm->formats |= SNDRV_PCM_FMTBIT_S32_LE;
+                               if (pcm->maxbps < 24)
+                                       pcm->maxbps = 24;
+                       }
+               }
+       }
+
+       if (!codec_pars)
+               return;
+
+       /* restrict the parameters by the values the codec provides */
+       pcm->rates &= codec_pars->rates;
+       pcm->formats &= codec_pars->formats;
+       pcm->channels_min = max(pcm->channels_min, codec_pars->channels_min);
+       pcm->channels_max = min(pcm->channels_max, codec_pars->channels_max);
+       pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps);
+}
+EXPORT_SYMBOL_HDA(hdmi_eld_update_pcm_info);
+
 #endif /* CONFIG_PROC_FS */
 
 int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid);
 int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t);
 void snd_hdmi_show_eld(struct hdmi_eld *eld);
+void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm,
+                             struct hda_pcm_stream *codec_pars);
 
 #ifdef CONFIG_PROC_FS
 int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld,
 
         * export one pcm per pipe
         */
        struct hda_pcm  pcm_rec[MAX_HDMI_CVTS];
+       struct hda_pcm_stream codec_pcm_pars[MAX_HDMI_CVTS];
 
        /*
         * nvhdmi specific
        return 0;
 }
 
+/*
+ * HDA PCM callbacks
+ */
+static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
+                        struct hda_codec *codec,
+                        struct snd_pcm_substream *substream)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_eld *eld;
+       struct hda_pcm_stream *codec_pars;
+       unsigned int idx;
+
+       for (idx = 0; idx < spec->num_cvts; idx++)
+               if (hinfo->nid == spec->cvt[idx])
+                       break;
+       if (snd_BUG_ON(idx >= spec->num_cvts) ||
+           snd_BUG_ON(idx >= spec->num_pins))
+               return -EINVAL;
+
+       /* save the PCM info the codec provides */
+       codec_pars = &spec->codec_pcm_pars[idx];
+       if (!codec_pars->rates)
+               *codec_pars = *hinfo;
+
+       eld = &spec->sink_eld[idx];
+       if (eld->sad_count > 0) {
+               hdmi_eld_update_pcm_info(eld, hinfo, codec_pars);
+               if (hinfo->channels_min > hinfo->channels_max ||
+                   !hinfo->rates || !hinfo->formats)
+                       return -ENODEV;
+       } else {
+               /* fallback to the codec default */
+               hinfo->channels_min = codec_pars->channels_min;
+               hinfo->channels_max = codec_pars->channels_max;
+               hinfo->rates = codec_pars->rates;
+               hinfo->formats = codec_pars->formats;
+               hinfo->maxbps = codec_pars->maxbps;
+       }
+       return 0;
+}
+
 /*
  * HDA/HDMI auto parsing
  */
 
        .substreams = 1,
        .channels_min = 2,
        .ops = {
+               .open = hdmi_pcm_open,
                .prepare = intel_hdmi_playback_pcm_prepare,
                .cleanup = intel_hdmi_playback_pcm_cleanup,
        },
 
 static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_89 = {
        .substreams = 1,
        .channels_min = 2,
-       .rates = SUPPORTED_RATES,
-       .maxbps = SUPPORTED_MAXBPS,
-       .formats = SUPPORTED_FORMATS,
        .ops = {
+               .open = hdmi_pcm_open,
                .prepare = nvhdmi_dig_playback_pcm_prepare_8ch_89,
                .cleanup = nvhdmi_playback_pcm_cleanup,
        },