Merge " "configs: enable 3D audio feature.""
diff --git a/configs/atoll/sound_trigger_platform_info.xml b/configs/atoll/sound_trigger_platform_info.xml
index 00ba7ec..dbbcb5f 100644
--- a/configs/atoll/sound_trigger_platform_info.xml
+++ b/configs/atoll/sound_trigger_platform_info.xml
@@ -130,7 +130,7 @@
             <!-- LPI: This mode type will be used for LPI usecases. -->
             <param lpi_mode="NON_LPI_BARGE_IN" />
             <param app_type="2" /> <!-- app type used in ACDB -->
-            <param in_channels="5"/> <!-- Module input channels -->
+            <param in_channels="3"/> <!-- Module input channels -->
             <param load_sound_model_ids="0x00012C1C, 0x0, 0x00012C14" />
             <param unload_sound_model_ids="0x00012C1C, 0x0, 0x00012C15" />
             <param confidence_levels_ids="0x00012C1C, 0x0, 0x00012C07" />
@@ -359,6 +359,6 @@
         <param app_type="69947" />
         <param sample_rate="16000" />
         <param bit_width="16" />
-        <param out_channels="5"/>
+        <param out_channels="3"/>
     </adm_config>
 </sound_trigger_platform_info>
diff --git a/configs/kona/audio_policy_configuration.xml b/configs/kona/audio_policy_configuration.xml
index d47ee6e..75b91a0 100755
--- a/configs/kona/audio_policy_configuration.xml
+++ b/configs/kona/audio_policy_configuration.xml
@@ -179,6 +179,11 @@
                               samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                               channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
                 </mixPort>
+                <mixPort name="quad mic" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                        samplingRates="48000"
+                        channelMasks="AUDIO_CHANNEL_INDEX_MASK_4"/>
+                </mixPort>
                 <mixPort name="voip_tx" role="sink"
                          flags="AUDIO_INPUT_FLAG_VOIP_TX">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
@@ -363,6 +368,8 @@
                        sources="Wired Headset Mic,BT SCO Headset Mic,FM Tuner,USB Device In,USB Headset In,Telephony Rx"/>
                 <route type="mix" sink="fast input"
                        sources="Built-In Mic,Built-In Back Mic,BT SCO Headset Mic,USB Device In,USB Headset In,Wired Headset Mic"/>
+                <route type="mix" sink="quad mic"
+                       sources="Built-In Mic,Built-In Back Mic,BT SCO Headset Mic,USB Device In,USB Headset In,Wired Headset Mic"/>
                 <route type="mix" sink="voip_tx"
                        sources="Built-In Mic,Built-In Back Mic,BT SCO Headset Mic,USB Device In,USB Headset In,Wired Headset Mic"/>
                 <route type="mix" sink="usb_surround_sound"
diff --git a/configs/kona/sound_trigger_platform_info.xml b/configs/kona/sound_trigger_platform_info.xml
index b4a611f..d8604b6 100644
--- a/configs/kona/sound_trigger_platform_info.xml
+++ b/configs/kona/sound_trigger_platform_info.xml
@@ -120,7 +120,7 @@
             <!-- fluence_type: "FLUENCE_MIC", "FLUENCE_DMIC", "FLUENCE_TMIC"   -->
             <!-- "FLUENCE_QMIC". Param value is valid when adm_cfg_profile -->
             <!-- is FFECNS -->
-            <param fluence_type="FLUENCE_TMIC" />
+            <param fluence_type="FLUENCE_DMIC" />
             <param execution_mode="ADSP" />
             <!-- lpi_mode: "NON_LPI_BARGE_IN", "NON_LPI", "LPI" -->
             <!-- NON_LPI_BARGE_IN: Default non-LPI mode type. lsm_usecase -->
@@ -131,7 +131,7 @@
             <!-- LPI: This mode type will be used for LPI usecases. -->
             <param lpi_mode="NON_LPI_BARGE_IN" />
             <param app_type="2" /> <!-- app type used in ACDB -->
-            <param in_channels="5"/> <!-- Module input channels -->
+            <param in_channels="3"/> <!-- Module input channels -->
             <param load_sound_model_ids="0x00012C1C, 0x0, 0x00012C14" />
             <param unload_sound_model_ids="0x00012C1C, 0x0, 0x00012C15" />
             <param confidence_levels_ids="0x00012C1C, 0x0, 0x00012C07" />
@@ -149,7 +149,7 @@
             <!-- fluence_type: "FLUENCE_MIC", "FLUENCE_DMIC", "FLUENCE_TMIC"   -->
             <!-- "FLUENCE_QMIC". Param value is valid when adm_cfg_profile -->
             <!-- is FFECNS -->
-            <param fluence_type="FLUENCE_TMIC" />
+            <param fluence_type="FLUENCE_DMIC" />
             <param execution_mode="ADSP" />
             <!-- lpi_mode: "NON_LPI_BARGE_IN", "NON_LPI", "LPI" -->
             <!-- NON_LPI_BARGE_IN: Default non-LPI mode type. lsm_usecase -->
@@ -160,7 +160,7 @@
             <!-- LPI: This mode type will be used for LPI usecases. -->
             <param lpi_mode="LPI" />
             <param app_type="2" /> <!-- app type used in ACDB -->
-            <param in_channels="3"/> <!-- Module input channels -->
+            <param in_channels="1"/> <!-- Module input channels -->
             <param load_sound_model_ids="0x00012C1C, 0x0, 0x00012C14" />
             <param unload_sound_model_ids="0x00012C1C, 0x0, 0x00012C15" />
             <param confidence_levels_ids="0x00012C1C, 0x0, 0x00012C07" />
@@ -389,7 +389,7 @@
         <param app_type="69947" />
         <param sample_rate="16000" />
         <param bit_width="16" />
-        <param out_channels="5"/>
+        <param out_channels="3"/>
     </adm_config>
 
     <adm_config>
diff --git a/configs/lahaina/lahaina.mk b/configs/lahaina/lahaina.mk
index e065edd..f9ed3b9 100644
--- a/configs/lahaina/lahaina.mk
+++ b/configs/lahaina/lahaina.mk
@@ -505,3 +505,5 @@
 PRODUCT_PACKAGES_DEBUG += \
     libadpcmdec
 endif
+
+AUDIO_FEATURE_ENABLED_GKI := true
diff --git a/configs/lito/audio_policy_configuration.xml b/configs/lito/audio_policy_configuration.xml
index 4095a6a..2ee18cd 100755
--- a/configs/lito/audio_policy_configuration.xml
+++ b/configs/lito/audio_policy_configuration.xml
@@ -179,6 +179,11 @@
                              samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                              channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
                 </mixPort>
+                <mixPort name="quad mic" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                        samplingRates="48000"
+                        channelMasks="AUDIO_CHANNEL_INDEX_MASK_4"/>
+                </mixPort>
                 <mixPort name="voip_tx" role="sink"
                          flags="AUDIO_INPUT_FLAG_VOIP_TX">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
@@ -363,6 +368,8 @@
                        sources="Wired Headset Mic,BT SCO Headset Mic,FM Tuner,USB Device In,USB Headset In,Telephony Rx"/>
                 <route type="mix" sink="fast input"
                        sources="Built-In Mic,Built-In Back Mic,BT SCO Headset Mic,USB Device In,USB Headset In,Wired Headset Mic"/>
+                <route type="mix" sink="quad mic"
+                       sources="Built-In Mic,Built-In Back Mic,BT SCO Headset Mic,USB Device In,USB Headset In,Wired Headset Mic"/>
                 <route type="mix" sink="voip_tx"
                        sources="Built-In Mic,Built-In Back Mic,BT SCO Headset Mic,USB Device In,USB Headset In,Wired Headset Mic"/>
                 <route type="mix" sink="usb_surround_sound"
diff --git a/configs/lito/sound_trigger_platform_info.xml b/configs/lito/sound_trigger_platform_info.xml
index 00ba7ec..dbbcb5f 100644
--- a/configs/lito/sound_trigger_platform_info.xml
+++ b/configs/lito/sound_trigger_platform_info.xml
@@ -130,7 +130,7 @@
             <!-- LPI: This mode type will be used for LPI usecases. -->
             <param lpi_mode="NON_LPI_BARGE_IN" />
             <param app_type="2" /> <!-- app type used in ACDB -->
-            <param in_channels="5"/> <!-- Module input channels -->
+            <param in_channels="3"/> <!-- Module input channels -->
             <param load_sound_model_ids="0x00012C1C, 0x0, 0x00012C14" />
             <param unload_sound_model_ids="0x00012C1C, 0x0, 0x00012C15" />
             <param confidence_levels_ids="0x00012C1C, 0x0, 0x00012C07" />
@@ -359,6 +359,6 @@
         <param app_type="69947" />
         <param sample_rate="16000" />
         <param bit_width="16" />
-        <param out_channels="5"/>
+        <param out_channels="3"/>
     </adm_config>
 </sound_trigger_platform_info>
diff --git a/hal/Android.mk b/hal/Android.mk
index 43f5c9c..3168ff9 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -131,6 +131,7 @@
                    audio_extn/source_track.c \
                    audio_extn/usb.c \
                    audio_extn/utils.c \
+                   audio_extn/device_utils.c \
                    voice_extn/compress_voip.c \
                    voice_extn/voice_extn.c
 
@@ -326,6 +327,11 @@
     LOCAL_CFLAGS += -DINSTANCE_ID_ENABLED
 endif
 
+# Hardware specific feature
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_GKI)), true)
+    LOCAL_CFLAGS += -DAUDIO_GKI_ENABLED
+endif
+
 # Legacy feature
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_KEEP_ALIVE_ARM_FFV)), true)
     LOCAL_CFLAGS += -DRUN_KEEP_ALIVE_IN_ARM_FFV
diff --git a/hal/audio_extn/Android.mk b/hal/audio_extn/Android.mk
index b5c32cd..b889212 100644
--- a/hal/audio_extn/Android.mk
+++ b/hal/audio_extn/Android.mk
@@ -136,7 +136,8 @@
   MULTIPLE_HW_VARIANTS_ENABLED := true
 endif
 
-LOCAL_SRC_FILES:= ssr.c
+LOCAL_SRC_FILES:= ssr.c \
+                  device_utils.c
 
 LOCAL_CFLAGS += \
     -Wall \
@@ -383,7 +384,8 @@
 endif
 
 LOCAL_SRC_FILES:= \
-        a2dp.c
+        a2dp.c \
+        device_utils.c
 
 LOCAL_CFLAGS += \
     -Wall \
@@ -514,7 +516,8 @@
 endif
 
 LOCAL_SRC_FILES:= \
-        hfp.c
+        hfp.c \
+        device_utils.c
 
 LOCAL_CFLAGS += \
     -Wall \
@@ -577,7 +580,8 @@
 endif
 
 LOCAL_SRC_FILES:= \
-        passthru.c
+        passthru.c \
+        device_utils.c
 
 LOCAL_CFLAGS += \
     -Wall \
@@ -779,7 +783,8 @@
 endif
 
 LOCAL_SRC_FILES:= \
-        maxxaudio.c
+        maxxaudio.c \
+        device_utils.c
 
 LOCAL_CFLAGS += \
     -Wall \
@@ -840,7 +845,8 @@
 endif
 
 LOCAL_SRC_FILES:= \
-        audiozoom.c
+        audiozoom.c \
+        device_utils.c
 
 LOCAL_CFLAGS += \
     -Wall \
@@ -904,7 +910,8 @@
 endif
 
 LOCAL_SRC_FILES:= \
-        auto_hal.c
+        auto_hal.c \
+        device_utils.c
 
 LOCAL_CFLAGS += \
     -Wall \
diff --git a/hal/audio_extn/a2dp.c b/hal/audio_extn/a2dp.c
index bffa3fd..e0aebf0 100644
--- a/hal/audio_extn/a2dp.c
+++ b/hal/audio_extn/a2dp.c
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -2786,7 +2786,7 @@
                 list_for_each(node, &a2dp.adev->usecase_list) {
                     uc_info = node_to_item(node, struct audio_usecase, list);
                     if (uc_info->stream.out && uc_info->type == PCM_PLAYBACK &&
-                         (uc_info->stream.out->devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
+                        is_a2dp_out_device_type(&uc_info->stream.out->device_list)) {
                         pthread_mutex_unlock(&a2dp.adev->lock);
                         fp_check_a2dp_restore(a2dp.adev, uc_info->stream.out, false);
                         pthread_mutex_lock(&a2dp.adev->lock);
@@ -2827,7 +2827,7 @@
                 list_for_each(node, &a2dp.adev->usecase_list) {
                     uc_info = node_to_item(node, struct audio_usecase, list);
                     if (uc_info->stream.out && uc_info->type == PCM_PLAYBACK &&
-                         (uc_info->stream.out->devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
+                        is_a2dp_out_device_type(&uc_info->stream.out->device_list)) {
                         pthread_mutex_unlock(&a2dp.adev->lock);
                         fp_check_a2dp_restore(a2dp.adev, uc_info->stream.out, true);
                         pthread_mutex_lock(&a2dp.adev->lock);
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 2d31509..620e7c6 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -1247,12 +1247,12 @@
         list_for_each(node, &adev->usecase_list) {
             usecase = node_to_item(node, struct audio_usecase, list);
             if (usecase->stream.out && usecase->type != PCM_CAPTURE) {
-                if (usecase->stream.out->devices == \
-                    AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
-                    usecase->stream.out->devices ==  \
-                    AUDIO_DEVICE_OUT_WIRED_HEADSET ||
-                    usecase->stream.out->devices ==  \
-                    AUDIO_DEVICE_OUT_EARPIECE) {
+                if (is_single_device_type_equal(&usecase->stream.out->device_list,
+                                AUDIO_DEVICE_OUT_WIRED_HEADPHONE) ||
+                    is_single_device_type_equal(&usecase->stream.out->device_list,
+                                AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+                    is_single_device_type_equal(&usecase->stream.out->device_list,
+                                AUDIO_DEVICE_OUT_EARPIECE)) {
                         select_devices(adev, usecase->id);
                         ALOGV("%s: switching device completed", __func__);
                         break;
@@ -3036,6 +3036,114 @@
     audio_extn_aptx_dec_set_license(adev);
 }
 
+#ifdef AUDIO_GKI_ENABLED
+int get_wma_dec_info(struct stream_out *out, struct str_parms *parms) {
+    int ret = 0;
+    char value[32];
+
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE, value, sizeof(value));
+    if (ret >= 0) {
+        out->compr_config.codec->options.wma_dec.avg_bit_rate = atoi(value);
+        out->is_compr_metadata_avail = true;
+    }
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_BLOCK_ALIGN, value, sizeof(value));
+    if (ret >= 0) {
+        out->compr_config.codec->options.wma_dec.super_block_align = atoi(value);
+        out->is_compr_metadata_avail = true;
+    }
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_BIT_PER_SAMPLE, value, sizeof(value));
+    if (ret >= 0) {
+        out->compr_config.codec->options.wma_dec.bits_per_sample = atoi(value);
+        out->is_compr_metadata_avail = true;
+    }
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_CHANNEL_MASK, value, sizeof(value));
+    if (ret >= 0) {
+        out->compr_config.codec->options.wma_dec.channelmask = atoi(value);
+        out->is_compr_metadata_avail = true;
+    }
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION, value, sizeof(value));
+    if (ret >= 0) {
+        out->compr_config.codec->options.wma_dec.encodeopt = atoi(value);
+        out->is_compr_metadata_avail = true;
+    }
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION1, value, sizeof(value));
+    if (ret >= 0) {
+        out->compr_config.codec->options.wma_dec.encodeopt1 = atoi(value);
+        out->is_compr_metadata_avail = true;
+    }
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION2, value, sizeof(value));
+    if (ret >= 0) {
+        out->compr_config.codec->options.wma_dec.encodeopt2 = atoi(value);
+        out->is_compr_metadata_avail = true;
+    }
+    ALOGV("WMA params: fmt %x, bit rate %x, balgn %x, sr %d, chmsk %x"
+            " encop %x, op1 %x, op2 %x",
+            out->compr_config.codec->format,
+            out->compr_config.codec->options.wma_dec.avg_bit_rate,
+            out->compr_config.codec->options.wma_dec.super_block_align,
+            out->compr_config.codec->options.wma_dec.bits_per_sample,
+            out->compr_config.codec->options.wma_dec.channelmask,
+            out->compr_config.codec->options.wma_dec.encodeopt,
+            out->compr_config.codec->options.wma_dec.encodeopt1,
+            out->compr_config.codec->options.wma_dec.encodeopt2);
+
+    return ret;
+}
+#else
+int get_wma_info(struct stream_out *out, struct str_parms *parms) {
+    int ret = 0;
+    char value[32];
+
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE, value, sizeof(value));
+    if (ret >= 0) {
+        out->compr_config.codec->options.wma.avg_bit_rate = atoi(value);
+        out->is_compr_metadata_avail = true;
+    }
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_BLOCK_ALIGN, value, sizeof(value));
+    if (ret >= 0) {
+        out->compr_config.codec->options.wma.super_block_align = atoi(value);
+        out->is_compr_metadata_avail = true;
+    }
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_BIT_PER_SAMPLE, value, sizeof(value));
+    if (ret >= 0) {
+        out->compr_config.codec->options.wma.bits_per_sample = atoi(value);
+        out->is_compr_metadata_avail = true;
+    }
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_CHANNEL_MASK, value, sizeof(value));
+    if (ret >= 0) {
+        out->compr_config.codec->options.wma.channelmask = atoi(value);
+        out->is_compr_metadata_avail = true;
+    }
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION, value, sizeof(value));
+    if (ret >= 0) {
+        out->compr_config.codec->options.wma.encodeopt = atoi(value);
+        out->is_compr_metadata_avail = true;
+    }
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION1, value, sizeof(value));
+    if (ret >= 0) {
+        out->compr_config.codec->options.wma.encodeopt1 = atoi(value);
+        out->is_compr_metadata_avail = true;
+    }
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION2, value, sizeof(value));
+    if (ret >= 0) {
+        out->compr_config.codec->options.wma.encodeopt2 = atoi(value);
+        out->is_compr_metadata_avail = true;
+    }
+    ALOGV("WMA params: fmt %x, bit rate %x, balgn %x, sr %d, chmsk %x"
+            " encop %x, op1 %x, op2 %x",
+            out->compr_config.codec->format,
+            out->compr_config.codec->options.wma.avg_bit_rate,
+            out->compr_config.codec->options.wma.super_block_align,
+            out->compr_config.codec->options.wma.bits_per_sample,
+            out->compr_config.codec->options.wma.channelmask,
+            out->compr_config.codec->options.wma.encodeopt,
+            out->compr_config.codec->options.wma.encodeopt1,
+            out->compr_config.codec->options.wma.encodeopt2);
+
+    return ret;
+}
+#endif
+
 int audio_extn_parse_compress_metadata(struct stream_out *out,
                                        struct str_parms *parms)
 {
@@ -3228,51 +3336,11 @@
             out->compr_config.codec->format = atoi(value);
             out->is_compr_metadata_avail = true;
         }
-        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE, value, sizeof(value));
-        if (ret >= 0) {
-            out->compr_config.codec->options.wma.avg_bit_rate = atoi(value);
-            out->is_compr_metadata_avail = true;
-        }
-        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_BLOCK_ALIGN, value, sizeof(value));
-        if (ret >= 0) {
-            out->compr_config.codec->options.wma.super_block_align = atoi(value);
-            out->is_compr_metadata_avail = true;
-        }
-        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_BIT_PER_SAMPLE, value, sizeof(value));
-        if (ret >= 0) {
-            out->compr_config.codec->options.wma.bits_per_sample = atoi(value);
-            out->is_compr_metadata_avail = true;
-        }
-        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_CHANNEL_MASK, value, sizeof(value));
-        if (ret >= 0) {
-            out->compr_config.codec->options.wma.channelmask = atoi(value);
-            out->is_compr_metadata_avail = true;
-        }
-        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION, value, sizeof(value));
-        if (ret >= 0) {
-            out->compr_config.codec->options.wma.encodeopt = atoi(value);
-            out->is_compr_metadata_avail = true;
-        }
-        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION1, value, sizeof(value));
-        if (ret >= 0) {
-            out->compr_config.codec->options.wma.encodeopt1 = atoi(value);
-            out->is_compr_metadata_avail = true;
-        }
-        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION2, value, sizeof(value));
-        if (ret >= 0) {
-            out->compr_config.codec->options.wma.encodeopt2 = atoi(value);
-            out->is_compr_metadata_avail = true;
-        }
-        ALOGV("WMA params: fmt %x, bit rate %x, balgn %x, sr %d, chmsk %x"
-                " encop %x, op1 %x, op2 %x",
-                out->compr_config.codec->format,
-                out->compr_config.codec->options.wma.avg_bit_rate,
-                out->compr_config.codec->options.wma.super_block_align,
-                out->compr_config.codec->options.wma.bits_per_sample,
-                out->compr_config.codec->options.wma.channelmask,
-                out->compr_config.codec->options.wma.encodeopt,
-                out->compr_config.codec->options.wma.encodeopt1,
-                out->compr_config.codec->options.wma.encodeopt2);
+#ifdef AUDIO_GKI_ENABLED
+	ret = get_wma_dec_info(out, parms);
+#else
+	ret = get_wma_info(out, parms);
+#endif
     }
 
     return ret;
@@ -3319,7 +3387,7 @@
     /* validate input params. Avoid updated channel mask if loopback device */
     if ((channel_count == 6) &&
         (in->format == AUDIO_FORMAT_PCM_16_BIT) &&
-        (!is_loopback_input_device(in->device))) {
+        (!is_loopback_input_device(get_device_types(&in->device_list)))) {
         switch (max_mic_count) {
             case 4:
                 config->channel_mask = AUDIO_CHANNEL_INDEX_MASK_4;
@@ -3594,13 +3662,13 @@
 
     adev_device_cfg_ptr = adev->device_cfg_params;
     /* Create an out stream to get snd device from audio device */
-    out.devices = device_cfg_params->device;
+    reassign_device_list(&out.device_list, device_cfg_params->device, "");
     out.sample_rate = device_cfg_params->sample_rate;
     snd_device = platform_get_output_snd_device(adev->platform, &out);
     backend_idx = platform_get_backend_index(snd_device);
 
     ALOGV("%s:: device %d sample_rate %d snd_device %d backend_idx %d",
-                __func__, out.devices, out.sample_rate, snd_device, backend_idx);
+                __func__, get_device_types(&out.device_list), out.sample_rate, snd_device, backend_idx);
 
     ALOGV("%s:: Device Config Params from Client samplerate %d  channels %d"
           " bit_width %d  format %d  device %d  channel_map[0] %d channel_map[1] %d"
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 986e24a..b01915a 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -680,7 +680,7 @@
 typedef int (*fp_platform_set_mic_mute_t)(void *, bool);
 //typedef int (*fp_platform_get_pcm_device_id_t)(audio_usecase_t, int);
 typedef void (*fp_platform_set_echo_reference_t)(struct audio_device *, bool,
-                                                            audio_devices_t);
+                                                     struct listnode *);
 typedef int (*fp_select_devices_t)(struct audio_device *, audio_usecase_t);
 typedef int (*fp_audio_extn_ext_hw_plugin_usecase_start_t)(void *,
                                                       struct audio_usecase *);
@@ -795,7 +795,7 @@
                                   struct listnode *streams_input_cfg_list);
 void audio_extn_utils_update_stream_output_app_type_cfg(void *platform,
                                   struct listnode *streams_output_cfg_list,
-                                  audio_devices_t devices,
+                                  struct listnode *devices,
                                   audio_output_flags_t flags,
                                   audio_format_t format,
                                   uint32_t sample_rate,
@@ -805,7 +805,7 @@
                                   struct stream_app_type_cfg *app_type_cfg);
 void audio_extn_utils_update_stream_input_app_type_cfg(void *platform,
                                   struct listnode *streams_input_cfg_list,
-                                  audio_devices_t devices,
+                                  struct listnode *devices,
                                   audio_input_flags_t flags,
                                   audio_format_t format,
                                   uint32_t sample_rate,
@@ -1063,7 +1063,7 @@
 void audio_extn_gef_init(struct audio_device *adev);
 void audio_extn_gef_deinit(struct audio_device *adev);
 
-void audio_extn_gef_notify_device_config(audio_devices_t audio_device,
+void audio_extn_gef_notify_device_config(struct listnode *audio_devices,
     audio_channel_mask_t channel_mask, int sample_rate, int acdb_id, int app_type);
 #ifndef INSTANCE_ID_ENABLED
 int audio_extn_gef_send_audio_cal(void* adev, int acdb_dev_id, int acdb_device_type,
@@ -1126,7 +1126,8 @@
 void audio_extn_fm_set_parameters(struct audio_device *adev,
                                    struct str_parms *parms);
 void audio_extn_fm_get_parameters(struct str_parms *query, struct str_parms *reply);
-void audio_extn_fm_route_on_selected_device(struct audio_device *adev, audio_devices_t device);
+void audio_extn_fm_route_on_selected_device(struct audio_device *adev,
+                                            struct listnode *devices);
 
 #ifndef APTX_DECODER_ENABLED
 #define audio_extn_aptx_dec_set_license(adev); (0)
diff --git a/hal/audio_extn/audiozoom.c b/hal/audio_extn/audiozoom.c
index 9958cc4..e2bde0f 100644
--- a/hal/audio_extn/audiozoom.c
+++ b/hal/audio_extn/audiozoom.c
@@ -203,7 +203,7 @@
         qdsp_audiozoom.zoom_param_id == 0)
         return -ENOSYS;
 
-    str_parms_add_int(parms, "cal_devid", in->device);
+    str_parms_add_int(parms, "cal_devid", get_device_types(&in->device_list));
     str_parms_add_int(parms, "cal_apptype", in->app_type_cfg.app_type);
     str_parms_add_int(parms, "cal_topoid", qdsp_audiozoom.topo_id);
     str_parms_add_int(parms, "cal_moduleid", qdsp_audiozoom.module_id);
diff --git a/hal/audio_extn/auto_hal.c b/hal/audio_extn/auto_hal.c
index 41b3762..580d446 100644
--- a/hal/audio_extn/auto_hal.c
+++ b/hal/audio_extn/auto_hal.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -230,7 +230,8 @@
                 ALOGV("Creating audio patch for external FM tuner");
                 uc_info->id = USECASE_AUDIO_FM_TUNER_EXT;
                 uc_info->type = PCM_PASSTHROUGH;
-                uc_info->devices = AUDIO_DEVICE_IN_FM_TUNER;
+                reassign_device_list(&uc_info->device_list, AUDIO_DEVICE_IN_FM_TUNER,
+                                     sources->ext.device.address);
                 uc_info->in_snd_device = SND_DEVICE_IN_CAPTURE_FM;
                 uc_info->out_snd_device = SND_DEVICE_OUT_BUS_MEDIA;
                 break;
@@ -599,8 +600,10 @@
                                                     streams_output_ctxt_t,
                                                     list);
                 /* limit audio gain support for bus device only */
-                if (out_ctxt->output->devices == AUDIO_DEVICE_OUT_BUS &&
-                    out_ctxt->output->devices == config->ext.device.type &&
+                if (is_single_device_type_equal(
+                        &out_ctxt->output->device_list, AUDIO_DEVICE_OUT_BUS) &&
+                    is_single_device_type_equal(&out_ctxt->output->device_list,
+                                                config->ext.device.type) &&
                     strcmp(out_ctxt->output->address,
                         config->ext.device.address) == 0) {
                     /* millibel = 1/100 dB = 1/1000 bel
@@ -710,7 +713,7 @@
 
     uc_downlink_info->type = PCM_HFP_CALL;
     uc_downlink_info->stream.out = adev->primary_output;
-    uc_downlink_info->devices = adev->primary_output->devices;
+    assign_devices(&uc_downlink_info->device_list, &adev->primary_output->device_list);
     uc_downlink_info->in_snd_device = SND_DEVICE_NONE;
     uc_downlink_info->out_snd_device = SND_DEVICE_NONE;
 
@@ -790,12 +793,16 @@
                                 audio_usecase_t uc_id)
 {
     snd_device_t snd_device = SND_DEVICE_NONE;
-    audio_devices_t out_device = AUDIO_DEVICE_NONE;
+    struct listnode out_devices;
     struct audio_usecase *usecase = NULL;
     struct stream_in *in = fp_adev_get_active_input(adev);
-    audio_devices_t in_device = ((in == NULL) ?
-                                    AUDIO_DEVICE_NONE : in->device)
-                                & ~AUDIO_DEVICE_BIT_IN;
+    struct listnode in_devices;
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    list_init(&in_devices);
+    if (in != NULL)
+        assign_devices(&in_devices, &in->device_list);
 
     if (uc_id == USECASE_INVALID) {
         ALOGE("%s: Invalid usecase (%d)", __func__, uc_id);
@@ -813,17 +820,18 @@
         return -EINVAL;
     }
 
-    out_device = usecase->stream.out->devices;
-    if (out_device == AUDIO_DEVICE_NONE ||
-        out_device & AUDIO_DEVICE_BIT_IN) {
-        ALOGE("%s: Invalid output devices (%#x)", __func__, out_device);
+    list_init(&out_devices);
+    assign_devices(&out_devices, &usecase->stream.out->device_list);
+    if (list_empty(&out_devices) ||
+        compare_device_type(&out_devices, AUDIO_DEVICE_BIT_IN)) {
+        ALOGE("%s: Invalid output devices (%#x)", __func__, get_device_types(&out_devices));
         return -EINVAL;
     }
 
     ALOGV("%s: output device(%#x), input device(%#x), usecase(%d)",
-        __func__, out_device, in_device, uc_id);
+        __func__, get_device_types(&out_devices), get_device_types(&in_devices), uc_id);
 
-    if (out_device & AUDIO_DEVICE_OUT_BUS) {
+    if (compare_device_type(&out_devices, AUDIO_DEVICE_OUT_BUS)) {
         /* usecase->id is token as judgement for HFP calls */
         switch (usecase->id) {
         case USECASE_AUDIO_HFP_SCO:
@@ -834,7 +842,7 @@
                 snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP;
             }
             if (adev->enable_hfp)
-                fp_platform_set_echo_reference(adev, true, out_device);
+                fp_platform_set_echo_reference(adev, false, &out_devices);
             break;
         case USECASE_AUDIO_HFP_SCO_DOWNLINK:
             snd_device = SND_DEVICE_IN_BT_SCO_MIC;
@@ -850,7 +858,7 @@
             return -EINVAL;
         }
     } else {
-        ALOGE("%s: Output devices (%#x) not supported", __func__, out_device);
+        ALOGE("%s: Output devices (%#x) not supported", __func__, get_device_types(&out_devices));
         return -EINVAL;
     }
 
@@ -861,7 +869,7 @@
                                 audio_usecase_t uc_id)
 {
     snd_device_t snd_device = SND_DEVICE_NONE;
-    audio_devices_t devices = AUDIO_DEVICE_NONE;
+    struct listnode devices;
     struct audio_usecase *usecase = NULL;
 
     if (uc_id == USECASE_INVALID) {
@@ -880,16 +888,18 @@
         return -EINVAL;
     }
 
-    devices = usecase->stream.out->devices;
-    if (devices == AUDIO_DEVICE_NONE ||
-        devices & AUDIO_DEVICE_BIT_IN) {
-        ALOGE("%s: Invalid output devices (%#x)", __func__, devices);
+    list_init(&devices);
+    assign_devices(&devices, &usecase->stream.out->device_list);
+    if (list_empty(&devices) ||
+        compare_device_type(&devices, AUDIO_DEVICE_BIT_IN)) {
+        ALOGE("%s: Invalid output devices (%#x)", __func__, get_device_types(&devices));
         return -EINVAL;
     }
 
-    ALOGV("%s: output devices(%#x), usecase(%d)", __func__, devices, uc_id);
+    ALOGV("%s: output devices(%#x), usecase(%d)", __func__,
+              get_device_types(&devices), uc_id);
 
-    if (devices & AUDIO_DEVICE_OUT_BUS) {
+    if (compare_device_type(&devices, AUDIO_DEVICE_OUT_BUS)) {
         /* usecase->id is token as judgement for HFP calls */
         switch (usecase->id) {
         case USECASE_AUDIO_HFP_SCO:
@@ -937,7 +947,7 @@
             return -EINVAL;
         }
     } else {
-        ALOGE("%s: Output devices (%#x) not supported", __func__, devices);
+        ALOGE("%s: Output devices (%#x) not supported", __func__, get_device_types(&devices));
         return -EINVAL;
     }
 
diff --git a/hal/audio_extn/compress_in.c b/hal/audio_extn/compress_in.c
index 6b525b0..fb8834d 100644
--- a/hal/audio_extn/compress_in.c
+++ b/hal/audio_extn/compress_in.c
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -281,6 +281,7 @@
     struct audio_config config = {.format = 0};
     int ret = 0, buffer_size = 0, meta_size = sizeof(struct snd_codec_metadata);
     cin_private_data_t *cin_data = NULL;
+    uint32_t compr_passthr = 0, flags = 0;
 
     if (!COMPRESSED_TIMESTAMP_FLAG &&
         (in->flags & (AUDIO_INPUT_FLAG_TIMESTAMP | AUDIO_INPUT_FLAG_PASSTHROUGH))) {
@@ -326,17 +327,26 @@
     cin_data->compr_config.codec->format = hal_format_to_alsa(in->format);
 
     if (cin_data->compr_config.codec->id == SND_AUDIOCODEC_PCM)
-        cin_data->compr_config.codec->compr_passthr = LEGACY_PCM;
+        compr_passthr = LEGACY_PCM;
     else if (cin_data->compr_config.codec->id == SND_AUDIOCODEC_IEC61937)
-        cin_data->compr_config.codec->compr_passthr = PASSTHROUGH_IEC61937;
+        compr_passthr = PASSTHROUGH_IEC61937;
     else
-        cin_data->compr_config.codec->compr_passthr = PASSTHROUGH_GEN;
+        compr_passthr = PASSTHROUGH_GEN;
 
     if (in->flags & AUDIO_INPUT_FLAG_FAST) {
         ALOGD("%s: Setting latency mode to true", __func__);
-        cin_data->compr_config.codec->flags |= audio_extn_utils_get_perf_mode_flag();
+        flags |= audio_extn_utils_get_perf_mode_flag();
     }
 
+#ifdef AUDIO_QGKI_ENABLED
+    /* out->compr_config.codec->reserved[0] is for compr_passthr */
+    cin_data->compr_config.codec->reserved[0] = compr_passthr;
+    /* out->compr_config.codec->reserved[1] is for flags */
+    cin_data->compr_config.codec->reserved[1] = flags;
+#else
+    cin_data->compr_config.codec->compr_passthr =  compr_passthr;
+    cin_data->compr_config.codec->flags = flags;
+#endif
     if ((in->flags & AUDIO_INPUT_FLAG_TIMESTAMP) ||
         (in->flags & AUDIO_INPUT_FLAG_PASSTHROUGH)) {
         compress_config_set_timstamp_flag(&cin_data->compr_config);
diff --git a/hal/audio_extn/device_utils.c b/hal/audio_extn/device_utils.c
new file mode 100644
index 0000000..e67676d
--- /dev/null
+++ b/hal/audio_extn/device_utils.c
@@ -0,0 +1,601 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of The Linux Foundation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "device_utils"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <stdlib.h>
+#include <hardware/audio.h>
+#include <cutils/list.h>
+#include <log/log.h>
+
+#include "device_utils.h"
+
+/*
+ * Below are the devices for which is back end is same, SLIMBUS_0_RX.
+ * All these devices are handled by the internal HW codec. We can
+ * enable any one of these devices at any time. An exception here is
+ * 44.1k headphone which uses different backend. This is filtered
+ * as different hal internal device in the code but remains same
+ * as standard android device AUDIO_DEVICE_OUT_WIRED_HEADPHONE
+ * for other layers.
+ */
+static const uint32_t AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND_ARRAY[] = {
+    AUDIO_DEVICE_OUT_EARPIECE,
+    AUDIO_DEVICE_OUT_SPEAKER,
+    AUDIO_DEVICE_OUT_WIRED_HEADSET,
+    AUDIO_DEVICE_OUT_WIRED_HEADPHONE,
+    AUDIO_DEVICE_OUT_LINE,
+    AUDIO_DEVICE_OUT_SPEAKER_SAFE,
+};
+
+/*
+ * Below are the input devices for which back end is same, SLIMBUS_0_TX.
+ * All these devices are handled by the internal HW codec. We can
+ * enable any one of these devices at any time
+ */
+static const uint32_t AUDIO_DEVICE_IN_ALL_CODEC_BACKEND_ARRAY[] = {
+    AUDIO_DEVICE_IN_BUILTIN_MIC,
+    AUDIO_DEVICE_IN_WIRED_HEADSET,
+    AUDIO_DEVICE_IN_VOICE_CALL,
+    AUDIO_DEVICE_IN_BACK_MIC,
+};
+
+static const uint32_t AUDIO_DEVICE_OUT_CODEC_BACKEND_CNT =
+                    AUDIO_ARRAY_SIZE(AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND_ARRAY);
+static const uint32_t AUDIO_DEVICE_IN_CODEC_BACKEND_CNT =
+                    AUDIO_ARRAY_SIZE(AUDIO_DEVICE_IN_ALL_CODEC_BACKEND_ARRAY);
+
+
+int list_length(struct listnode *list)
+{
+    struct listnode *node;
+    int length = 0;
+
+    if (list == NULL)
+        goto done;
+
+    for (node = list->next; node != list; node = node->next)
+        ++length;
+done:
+    return length;
+}
+
+/*
+ * Returns true if devices list contains input device type.
+ */
+bool is_audio_in_device_type(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && audio_is_input_device(item->type)) {
+            ALOGV("%s: in device %#x", __func__, item->type);
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Returns true if devices list contains output device type.
+ */
+bool is_audio_out_device_type(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && audio_is_output_device(item->type)) {
+            ALOGV("%s: out device %#x", __func__, item->type);
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Returns true if devices list contains codec backend
+ * input device type.
+ */
+bool is_codec_backend_in_device_type(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item == NULL)
+            return false;
+        for (int i = 0; i < AUDIO_DEVICE_IN_CODEC_BACKEND_CNT; i++) {
+            if (item->type == AUDIO_DEVICE_IN_ALL_CODEC_BACKEND_ARRAY[i]) {
+                ALOGV("%s: codec backend in device %#x", __func__, item->type);
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+/*
+ * Returns true if devices list contains codec backend
+ * output device type.
+ */
+bool is_codec_backend_out_device_type(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item == NULL)
+            return false;
+        for (int i = 0; i < AUDIO_DEVICE_OUT_CODEC_BACKEND_CNT; i++) {
+            if (item->type == AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND_ARRAY[i]) {
+                ALOGV("%s: codec backend out device %#x", __func__, item->type);
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+/* Returns true if USB input device is found in passed devices list */
+bool is_usb_in_device_type(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && audio_is_usb_in_device(item->type)) {
+            ALOGV("%s: USB in device %#x", __func__, item->type);
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Returns true if USB output device is found in passed devices list
+ */
+bool is_usb_out_device_type(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && audio_is_usb_out_device(item->type)) {
+            ALOGV("%s: USB out device %#x address %s", __func__,
+                   item->type, item->address);
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Returns USB device address information (card, device)
+ */
+const char *get_usb_device_address(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && (audio_is_usb_out_device(item->type) ||
+                        audio_is_usb_in_device(item->type))) {
+            ALOGV("%s: USB device %#x address %s", __func__,
+                   item->type, item->address);
+            return (const char *)&item->address[0];
+        }
+    }
+    return "";
+}
+
+/*
+ * Returns true if SCO output device is found in passed devices list
+ */
+bool is_sco_in_device_type(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL &&
+                audio_is_bluetooth_in_sco_device(item->type)) {
+            ALOGV("%s: SCO in device %#x", __func__, item->type);
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Returns true if SCO output device is found in passed devices list
+ */
+bool is_sco_out_device_type(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL &&
+                audio_is_bluetooth_out_sco_device(item->type)) {
+            ALOGV("%s: SCO out device %#x", __func__, item->type);
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Returns true if A2DP input device is found in passed devices list
+ */
+bool is_a2dp_in_device_type(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && audio_is_a2dp_in_device(item->type)) {
+            ALOGV("%s: A2DP in device %#x", __func__, item->type);
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Returns true if A2DP output device is found in passed devices list
+ */
+bool is_a2dp_out_device_type(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && audio_is_a2dp_out_device(item->type)) {
+            ALOGV("%s: A2DP out device %#x", __func__, item->type);
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Clear device list
+ * Operation: devices = {};
+ */
+
+int clear_devices(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return 0;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL) {
+            list_remove(&item->list);
+            free(item);
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * Check if a device with given type is present in devices list
+ */
+bool compare_device_type(struct listnode *devices, audio_devices_t device_type)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && (item->type == device_type)) {
+            ALOGV("%s: device types %d match", __func__, device_type);
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Returns true if intersection of d1 and d2 is not NULL
+ */
+bool compare_devices_for_any_match(struct listnode *d1, struct listnode *d2)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (d1 == NULL || d2 == NULL)
+        return false;
+
+    list_for_each (node, d1) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && compare_device_type(d2, item->type))
+            return true;
+    }
+    return false;
+}
+
+/*
+ * Returns all device types from list in bitfield
+ * ToDo: Use of this function is not recommended.
+ * It has been introduced for compatability with legacy functions.
+ * This can be removed once audio HAL switches to device
+ * list usage for all audio extensions.
+ */
+audio_devices_t get_device_types(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+    audio_devices_t device_type = AUDIO_DEVICE_NONE;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL)
+            device_type |= item->type;
+    }
+    return device_type;
+}
+
+/*
+ * If single device in devices list is equal to passed type
+ * type should represent a single device.
+ */
+bool is_single_device_type_equal(struct listnode *devices,
+                                 audio_devices_t type)
+{
+    struct listnode *node = devices;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    if (list_length(devices) == 1) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && (item->type == type))
+            return true;
+    }
+    return false;
+}
+
+/*
+ * Returns true if lists are equal in terms of device type
+ * ToDO: Check if device addresses are also equal in the future
+ */
+bool compare_devices(struct listnode *d1, struct listnode *d2)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (d1 == NULL && d2 == NULL)
+        return true;
+
+    if (d1 == NULL || d2 == NULL ||
+            (list_length(d1) != list_length(d2)))
+        return false;
+
+    list_for_each (node, d1) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && !compare_device_type(d2, item->type))
+            return false;
+    }
+    return true;
+}
+
+/*
+ * Add or remove device from list denoted by head
+ */
+int update_device_list(struct listnode *head, audio_devices_t type,
+                       const char* address, bool add_device)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+    struct audio_device_info *device = NULL;
+    int ret = 0;
+
+    if (head == NULL)
+        goto done;
+
+    if (type == AUDIO_DEVICE_NONE) {
+        ALOGE("%s: Invalid device: %#x", __func__, type);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    list_for_each (node, head) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && (item->type == type)) {
+            device = item;
+            break;
+        }
+    }
+
+    if (add_device) {
+        if (device == NULL) {
+            device = (struct audio_device_info *)
+                        calloc (1, sizeof(struct audio_device_info));
+            if (!device) {
+                ALOGE("%s: Cannot allocate memory for device_info", __func__);
+                ret = -ENOMEM;
+                goto done;
+            }
+            device->type = type;
+            list_add_tail(head, &device->list);
+        }
+        strlcpy(device->address, address, AUDIO_DEVICE_MAX_ADDRESS_LEN);
+        ALOGV("%s: Added device type %#x, address %s", __func__, type, address);
+    } else {
+        if (device != NULL) {
+            list_remove(&device->list);
+            free(device);
+            ALOGV("%s: Removed device type %#x, address %s", __func__, type, address);
+        }
+    }
+done:
+    return ret;
+}
+
+/*
+ * Assign source device list to destination device list
+ * Operation: dest list = source list
+ */
+int assign_devices(struct listnode *dest, const struct listnode *source)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+    int ret = 0;
+
+    if (source == NULL || dest == NULL)
+        return ret;
+
+    if (!list_empty(dest))
+        clear_devices(dest);
+
+    list_for_each (node, source) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL)
+            ret = update_device_list(dest, item->type, item->address, true);
+    }
+    return ret;
+}
+
+/*
+ * Assign output devices from source device list to destination device list
+ * Operation: dest devices = source output devices
+ */
+int assign_output_devices(struct listnode *dest, const struct listnode *source)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+    int ret = 0;
+
+    if (source == NULL || dest == NULL)
+        return ret;
+
+    if (!list_empty(dest))
+        clear_devices(dest);
+
+    list_for_each (node, source) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && audio_is_output_device(item->type))
+            ret = update_device_list(dest, item->type, item->address, true);
+    }
+    return ret;
+}
+
+/*
+ * Clear device list and replace it with single device
+ */
+int reassign_device_list(struct listnode *device_list,
+                            audio_devices_t type, char *address)
+{
+    if (device_list == NULL)
+        return 0;
+
+    if (!list_empty(device_list))
+        clear_devices(device_list);
+
+    return update_device_list(device_list, type, address, true);
+}
+
+/*
+ * Append source devices to destination devices
+ * Operation: dest devices |= source devices
+ */
+int append_devices(struct listnode *dest, const struct listnode *source)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+    int ret = 0;
+
+    if (source == NULL || dest == NULL)
+        return ret;
+
+    list_for_each (node, source) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL)
+            ret = update_device_list(dest, item->type, item->address, true);
+    }
+    return ret;
+}
diff --git a/hal/audio_extn/device_utils.h b/hal/audio_extn/device_utils.h
new file mode 100644
index 0000000..b6d4c9b
--- /dev/null
+++ b/hal/audio_extn/device_utils.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of The Linux Foundation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AUDIO_HW_EXTN_DEVICE_UTILS_H
+#define AUDIO_HW_EXTN_DEVICE_UTILS_H
+
+struct audio_device_info {
+    struct listnode list;
+    audio_devices_t type;
+    char address[AUDIO_DEVICE_MAX_ADDRESS_LEN];
+};
+
+int list_length(struct listnode *list);
+bool is_audio_in_device_type(struct listnode *devices);
+bool is_audio_out_device_type(struct listnode *devices);
+bool is_codec_backend_in_device_type(struct listnode *devices);
+bool is_codec_backend_out_device_type(struct listnode *devices);
+bool is_usb_in_device_type(struct listnode *devices);
+bool is_usb_out_device_type(struct listnode *devices);
+const char *get_usb_device_address(struct listnode *devices);
+bool is_sco_in_device_type(struct listnode *devices);
+bool is_sco_out_device_type(struct listnode *devices);
+bool is_a2dp_in_device_type(struct listnode *devices);
+bool is_a2dp_out_device_type(struct listnode *devices);
+int clear_devices(struct listnode *devices);
+bool compare_device_type(struct listnode *devices, audio_devices_t device_type);
+bool compare_devices_for_any_match(struct listnode *d1, struct listnode *d2);
+audio_devices_t get_device_types(struct listnode *devices);
+bool is_single_device_type_equal(struct listnode *devices,
+                                 audio_devices_t type);
+bool compare_devices(struct listnode *d1, struct listnode *d2);
+int update_device_list(struct listnode *head, audio_devices_t type,
+                       const char* address, bool add_device);
+int assign_devices(struct listnode *dest, const struct listnode *source);
+int assign_output_devices(struct listnode *dest, const struct listnode *source);
+int reassign_device_list(struct listnode *device_list,
+                            audio_devices_t type, char *address);
+int append_devices(struct listnode *dest, const struct listnode *source);
+
+#endif
diff --git a/hal/audio_extn/dolby.c b/hal/audio_extn/dolby.c
index 335cfbd..f4a1a97 100644
--- a/hal/audio_extn/dolby.c
+++ b/hal/audio_extn/dolby.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2017, 2020, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2010 The Android Open Source Project
@@ -246,7 +246,7 @@
     list_for_each(node, &adev->usecase_list) {
         usecase = node_to_item(node, struct audio_usecase, list);
         if (usecase->stream.out && (usecase->type == PCM_PLAYBACK) &&
-            (usecase->devices & ddp_dev) &&
+            (compare_device_type(&usecase->device_list, ddp_dev)) &&
             (usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
             ((usecase->stream.out->format == AUDIO_FORMAT_AC3) ||
              (usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
@@ -264,7 +264,7 @@
     list_for_each(node, &adev->usecase_list) {
         usecase = node_to_item(node, struct audio_usecase, list);
         if (usecase->stream.out && (usecase->type == PCM_PLAYBACK) &&
-            (usecase->devices & AUDIO_DEVICE_OUT_ALL) &&
+            is_audio_out_device_type(&usecase->device_list) &&
             (usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
             ((usecase->stream.out->format == AUDIO_FORMAT_AC3) ||
              (usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
@@ -273,11 +273,14 @@
              * Use wfd /hdmi sink channel cap for dolby params if device is wfd
              * or hdmi. Otherwise use stereo configuration
              */
-            int channel_cap = usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL ?
+            int channel_cap = compare_device_type(&usecase->device_list,
+                                                  AUDIO_DEVICE_OUT_AUX_DIGITAL) ?
                               adev->cur_hdmi_channels :
-                              usecase->devices & AUDIO_DEVICE_OUT_PROXY ?
+                              compare_device_type(&usecase->device_list,
+                                                  AUDIO_DEVICE_OUT_PROXY) ?
                               adev->cur_wfd_channels : 2;
-            send_ddp_endp_params_stream(usecase->stream.out, usecase->devices,
+            send_ddp_endp_params_stream(usecase->stream.out,
+                                        get_device_types(&usecase->device_list),
                                         channel_cap, false /* set cache */);
         }
     }
@@ -302,7 +305,7 @@
                             sizeof(value));
     if (ret >= 0) {
         ddp_dev = atoi(value);
-        if (!(AUDIO_DEVICE_OUT_ALL & ddp_dev))
+        if (!audio_is_output_device(ddp_dev))
             return;
     } else
         return;
@@ -376,7 +379,7 @@
         usecase = node_to_item(node, struct audio_usecase, list);
         if ((usecase->type == PCM_PLAYBACK) &&
             (usecase->id != USECASE_AUDIO_PLAYBACK_LOW_LATENCY)) {
-            endpoint |= usecase->devices & AUDIO_DEVICE_OUT_ALL;
+            endpoint |= is_audio_out_device_type(&usecase->device_list);
             send = true;
         }
     }
@@ -528,7 +531,7 @@
         usecase = node_to_item(node, struct audio_usecase, list);
         if ((usecase->type == PCM_PLAYBACK) &&
             (usecase->id != USECASE_AUDIO_PLAYBACK_LOW_LATENCY)) {
-            endpoint |= usecase->devices & AUDIO_DEVICE_OUT_ALL;
+            endpoint |= is_audio_out_device_type(&usecase->device_list);
             send = true;
         }
     }
diff --git a/hal/audio_extn/ffv.c b/hal/audio_extn/ffv.c
index b97eedc..fe6ffa6 100644
--- a/hal/audio_extn/ffv.c
+++ b/hal/audio_extn/ffv.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -365,13 +365,13 @@
 bool  audio_extn_ffv_check_usecase(struct stream_in *in) {
     int ret = false;
     int channel_count = audio_channel_count_from_in_mask(in->channel_mask);
-    audio_devices_t devices = in->device;
     audio_source_t source = in->source;
 
     if ((audio_extn_ffv_get_enabled()) &&
             (channel_count == 1) &&
             (AUDIO_SOURCE_MIC == source) &&
-            ((AUDIO_DEVICE_IN_BUILTIN_MIC == devices) || (AUDIO_DEVICE_IN_BACK_MIC == devices)) &&
+            (is_single_device_type_equal(&in->device_list, AUDIO_DEVICE_IN_BUILTIN_MIC) ||
+             is_single_device_type_equal(&in->device_list, AUDIO_DEVICE_IN_BACK_MIC)) &&
             (in->format == AUDIO_FORMAT_PCM_16_BIT) &&
             (in->sample_rate == FFV_SAMPLING_RATE_16000)) {
         in->config.channels = channel_count;
diff --git a/hal/audio_extn/fm.c b/hal/audio_extn/fm.c
index 435c377..a0c2410 100644
--- a/hal/audio_extn/fm.c
+++ b/hal/audio_extn/fm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -182,7 +182,7 @@
     fm_out->format = AUDIO_FORMAT_PCM_16_BIT;
     fm_out->usecase = USECASE_AUDIO_PLAYBACK_FM;
     fm_out->config = pcm_config_fm;
-    fm_out->devices = outputDevices;
+    reassign_device_list(&fm_out->device_list, outputDevices, "");
     fmmod.is_fm_running = true;
 
     uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
@@ -195,7 +195,7 @@
     uc_info->id = USECASE_AUDIO_PLAYBACK_FM;
     uc_info->type = PCM_PLAYBACK;
     uc_info->stream.out = fm_out;
-    uc_info->devices = outputDevices;
+    reassign_device_list(&uc_info->device_list, outputDevices, "");
     uc_info->in_snd_device = SND_DEVICE_NONE;
     uc_info->out_snd_device = SND_DEVICE_NONE;
 
@@ -240,7 +240,7 @@
     pcm_start(fmmod.fm_pcm_rx);
     pcm_start(fmmod.fm_pcm_tx);
 
-    fmmod.fm_device = fm_out->devices;
+    fmmod.fm_device = get_device_types(&fm_out->device_list);
 
     ALOGD("%s: exit: status(%d)", __func__, ret);
     return 0;
@@ -388,7 +388,8 @@
     ALOGV("%s: exit", __func__);
 }
 
-void audio_extn_fm_route_on_selected_device(struct audio_device *adev, audio_devices_t device)
+void audio_extn_fm_route_on_selected_device(struct audio_device *adev,
+                                            struct listnode *devices)
 {
     struct listnode *node;
     struct audio_usecase *usecase;
@@ -397,10 +398,10 @@
         list_for_each(node, &adev->usecase_list) {
             usecase = node_to_item(node, struct audio_usecase, list);
             if (usecase->id == USECASE_AUDIO_PLAYBACK_FM) {
-                if (fmmod.fm_device != device) {
+                if (fmmod.fm_device != get_device_types(devices)) {
                     ALOGV("%s selected routing device %x current device %x"
                           "are different, reroute on selected device", __func__,
-                          fmmod.fm_device, device);
+                          fmmod.fm_device, get_device_types(devices));
                     select_devices(adev, usecase->id);
                 }
             }
diff --git a/hal/audio_extn/gef.c b/hal/audio_extn/gef.c
index 83e9d45..69b1e41 100644
--- a/hal/audio_extn/gef.c
+++ b/hal/audio_extn/gef.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -427,15 +427,15 @@
 #endif
 
 //this will be called from HAL to notify GEF of new device configuration
-void audio_extn_gef_notify_device_config(audio_devices_t audio_device,
+void audio_extn_gef_notify_device_config(struct listnode *audio_devices,
     audio_channel_mask_t channel_mask, int sample_rate, int acdb_id, int app_type)
 {
     ALOGV("%s: Enter", __func__);
 
     //call into GEF to share channel mask and device info
     if (gef_hal_handle.handle && gef_hal_handle.device_config_cb) {
-        gef_hal_handle.device_config_cb(gef_hal_handle.gef_ptr, audio_device, channel_mask,
-            sample_rate, acdb_id, app_type);
+        gef_hal_handle.device_config_cb(gef_hal_handle.gef_ptr, get_device_types(audio_devices),
+            channel_mask, sample_rate, acdb_id, app_type);
     }
 
     ALOGV("%s: Exit", __func__);
diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c
index e646bc1..2b63277 100644
--- a/hal/audio_extn/hfp.c
+++ b/hal/audio_extn/hfp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
@@ -309,7 +309,7 @@
     uc_info->id = hfpmod.ucid;
     uc_info->type = PCM_HFP_CALL;
     uc_info->stream.out = adev->primary_output;
-    uc_info->devices = adev->primary_output->devices;
+    assign_devices(&uc_info->device_list, &adev->primary_output->device_list);
     uc_info->in_snd_device = SND_DEVICE_NONE;
     uc_info->out_snd_device = SND_DEVICE_NONE;
 
@@ -440,6 +440,8 @@
 {
     int32_t ret = 0;
     struct audio_usecase *uc_info;
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
 
     ALOGD("%s: enter", __func__);
     hfpmod.is_hfp_running = false;
@@ -484,7 +486,7 @@
     }
 
     /* 2. Disable echo reference while stopping hfp */
-    fp_platform_set_echo_reference(adev, false, uc_info->devices);
+    fp_platform_set_echo_reference(adev, false, &uc_info->device_list);
 
     /* 3. Get and set stream specific mixer controls */
     fp_disable_audio_route(adev, uc_info);
diff --git a/hal/audio_extn/hw_loopback.c b/hal/audio_extn/hw_loopback.c
index afc029b..0b81fde 100644
--- a/hal/audio_extn/hw_loopback.c
+++ b/hal/audio_extn/hw_loopback.c
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -496,7 +496,8 @@
     uc_info_rx->id = USECASE_AUDIO_TRANSCODE_LOOPBACK_RX;
     uc_info_rx->type = audio_loopback_mod->uc_type_rx;
     uc_info_rx->stream.inout = &active_loopback_patch->patch_stream;
-    uc_info_rx->devices = active_loopback_patch->patch_stream.out_config.devices;
+    assign_devices(&uc_info_rx->device_list,
+                   &active_loopback_patch->patch_stream.out_config.device_list);
     uc_info_rx->in_snd_device = SND_DEVICE_NONE;
     uc_info_rx->out_snd_device = SND_DEVICE_NONE;
 
@@ -504,7 +505,8 @@
     uc_info_tx->id = USECASE_AUDIO_TRANSCODE_LOOPBACK_TX;
     uc_info_tx->type = audio_loopback_mod->uc_type_tx;
     uc_info_tx->stream.inout = &active_loopback_patch->patch_stream;
-    uc_info_tx->devices = active_loopback_patch->patch_stream.in_config.devices;
+    assign_devices(&uc_info_tx->device_list,
+                   &active_loopback_patch->patch_stream.in_config.device_list);
     uc_info_tx->in_snd_device = SND_DEVICE_NONE;
     uc_info_tx->out_snd_device = SND_DEVICE_NONE;
 
@@ -678,7 +680,7 @@
     stream_cfg->sample_rate = port_cfg->sample_rate;
     stream_cfg->channel_mask = port_cfg->channel_mask;
     stream_cfg->format = port_cfg->format;
-    stream_cfg->devices = port_cfg->ext.device.type;
+    reassign_device_list(&stream_cfg->device_list, port_cfg->ext.device.type, "");
     stream_cfg->bit_width = format_to_bitwidth(port_cfg->format);
 }
 /* API to create audio patch */
diff --git a/hal/audio_extn/keep_alive.c b/hal/audio_extn/keep_alive.c
index 79f2bb0..15725b2 100644
--- a/hal/audio_extn/keep_alive.c
+++ b/hal/audio_extn/keep_alive.c
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014-2018, 2020, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -72,7 +72,7 @@
     ka_mode_t prev_mode;
     bool done;
     void * userdata;
-    audio_devices_t active_devices;
+    struct listnode active_devices;
 } keep_alive_t;
 
 struct keep_alive_cmd {
@@ -128,7 +128,7 @@
     }
     ka.done = false;
     ka.prev_mode = KEEP_ALIVE_OUT_NONE;
-    ka.active_devices = AUDIO_DEVICE_NONE;
+    list_init(&ka.active_devices);
 
     pthread_mutex_init(&ka.lock, (const pthread_mutexattr_t *) NULL);
     pthread_cond_init(&ka.cond, (const pthread_condattr_t *) NULL);
@@ -164,38 +164,38 @@
     ALOGV("%s deinit done", __func__);
 }
 
-audio_devices_t get_device_id_from_mode(ka_mode_t ka_mode)
+void get_device_id_from_mode(ka_mode_t ka_mode,
+                             struct listnode *out_devices)
 {
     struct audio_device * adev = (struct audio_device *)ka.userdata;
-    audio_devices_t out_device = AUDIO_DEVICE_NONE;
+
     switch (ka_mode)
     {
         case KEEP_ALIVE_OUT_PRIMARY:
             if (adev->primary_output) {
-                if (adev->primary_output->devices & AUDIO_DEVICE_OUT_ALL)
-                    out_device = adev->primary_output->devices & AUDIO_DEVICE_OUT_ALL;
+                if (is_audio_out_device_type(&adev->primary_output->device_list))
+                    assign_output_devices(out_devices, &adev->primary_output->device_list);
                 else
-                    out_device = AUDIO_DEVICE_OUT_SPEAKER;
+                    reassign_device_list(out_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
             }
             else {
-                out_device = AUDIO_DEVICE_OUT_SPEAKER;
+                reassign_device_list(out_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
             }
             break;
 
         case KEEP_ALIVE_OUT_HDMI:
-            out_device = AUDIO_DEVICE_OUT_AUX_DIGITAL;
+            reassign_device_list(out_devices, AUDIO_DEVICE_OUT_AUX_DIGITAL, "");
             break;
-
+        case KEEP_ALIVE_OUT_NONE:
         default:
-            out_device = AUDIO_DEVICE_NONE;
+            break;
     }
-    return out_device;
 }
 
 void keep_alive_start(ka_mode_t ka_mode)
 {
     struct audio_device * adev = (struct audio_device *)ka.userdata;
-    audio_devices_t out_devices = AUDIO_DEVICE_NONE;
+    struct listnode out_devices;
 
     pthread_mutex_lock(&ka.lock);
     ALOGV("%s: mode %x", __func__, ka_mode);
@@ -204,27 +204,32 @@
         goto exit;
     }
 
-    out_devices = get_device_id_from_mode(ka_mode);
-    if ((out_devices == ka.active_devices) && (ka.state == STATE_ACTIVE)) {
-        ALOGV(" %s : Already feeding silence to device %x",__func__, out_devices);
+    list_init(&out_devices);
+    get_device_id_from_mode(ka_mode, &out_devices);
+    if (compare_devices(&out_devices, &ka.active_devices) &&
+            (ka.state == STATE_ACTIVE)) {
+        ALOGV(" %s : Already feeding silence to device %x",__func__,
+              get_device_types(&out_devices));
         ka.prev_mode |= ka_mode;
         goto exit;
     }
-    ALOGV(" %s : active devices %x, new device %x",__func__, ka.active_devices, out_devices);
+    ALOGV(" %s : active devices %x, new device %x",__func__,
+           get_device_types(&ka.active_devices), get_device_types(&out_devices));
 
-    if (out_devices == AUDIO_DEVICE_NONE)
+    if (list_empty(&out_devices))
         goto exit;
 
     if (audio_extn_passthru_is_active()) {
-        ka.active_devices &= ~AUDIO_DEVICE_OUT_AUX_DIGITAL;
-        if(ka.active_devices == AUDIO_DEVICE_NONE)
+        update_device_list(&ka.active_devices, AUDIO_DEVICE_OUT_AUX_DIGITAL,
+                           "", false);
+        if (list_empty(&ka.active_devices))
             goto exit;
     }
 
-    ka.active_devices |= out_devices;
+    append_devices(&ka.active_devices, &out_devices);
     ka.prev_mode |= ka_mode;
     if (ka.state == STATE_ACTIVE) {
-        ka.out->devices = ka.active_devices;
+        assign_devices(&ka.out->device_list, &ka.active_devices);
         select_devices(adev, USECASE_AUDIO_PLAYBACK_SILENCE);
     } else if (ka.state == STATE_IDLE) {
         keep_alive_start_l();
@@ -263,7 +268,7 @@
     }
 
     ka.out->flags = 0;
-    ka.out->devices = ka.active_devices;
+    assign_devices(&ka.out->device_list, &ka.active_devices);
     ka.out->dev = adev;
     ka.out->format = AUDIO_FORMAT_PCM_16_BIT;
     ka.out->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
@@ -274,6 +279,7 @@
     usecase->stream.out = ka.out;
     usecase->type = PCM_PLAYBACK;
     usecase->id = USECASE_AUDIO_PLAYBACK_SILENCE;
+    list_init(&usecase->device_list);
     usecase->out_snd_device = SND_DEVICE_NONE;
     usecase->in_snd_device = SND_DEVICE_NONE;
 
@@ -304,7 +310,7 @@
 void keep_alive_stop(ka_mode_t ka_mode)
 {
     struct audio_device * adev = (struct audio_device *)ka.userdata;
-    audio_devices_t out_devices;
+    struct listnode out_devices;
     if (ka.state == STATE_DISABLED)
         return;
 
@@ -312,21 +318,23 @@
 
     ALOGV("%s: mode %x", __func__, ka_mode);
     if (ka_mode && (ka.state != STATE_ACTIVE)) {
+        get_device_id_from_mode(ka_mode, &out_devices);
         ALOGV(" %s : Can't stop, keep_alive",__func__);
-        ALOGV(" %s : keep_alive is not running on device %x",__func__, get_device_id_from_mode(ka_mode));
+        ALOGV(" %s : keep_alive is not running on device %x",__func__,
+                get_device_types(&out_devices));
         ka.prev_mode |= ka_mode;
         goto exit;
     }
-    out_devices = get_device_id_from_mode(ka_mode);
+    get_device_id_from_mode(ka_mode, &out_devices);
     if (ka.prev_mode & ka_mode) {
         ka.prev_mode &= ~ka_mode;
-        ka.active_devices = get_device_id_from_mode(ka.prev_mode);
+        get_device_id_from_mode(ka.prev_mode, &ka.active_devices);
     }
 
-    if (ka.active_devices == AUDIO_DEVICE_NONE) {
+    if (list_empty(&ka.active_devices)) {
         keep_alive_cleanup();
-    } else if (ka.out->devices != ka.active_devices){
-        ka.out->devices = ka.active_devices;
+    } else if (!compare_devices(&ka.out->device_list, &ka.active_devices)) {
+        assign_devices(&ka.out->device_list, &ka.active_devices);
         select_devices(adev, USECASE_AUDIO_PLAYBACK_SILENCE);
     }
 exit:
@@ -362,7 +370,7 @@
     }
     pcm_close(ka.pcm);
     ka.pcm = NULL;
-    ka.active_devices = KEEP_ALIVE_OUT_NONE;
+    clear_devices(&ka.active_devices);
     return 0;
 }
 
diff --git a/hal/audio_extn/maxxaudio.c b/hal/audio_extn/maxxaudio.c
index a8f09fc..88de2f2 100644
--- a/hal/audio_extn/maxxaudio.c
+++ b/hal/audio_extn/maxxaudio.c
@@ -100,7 +100,7 @@
 
 typedef struct ma_audio_cal_common_settings {
     unsigned int app_type;
-    unsigned int device;
+    struct listnode devices;
 } ma_audio_cal_common_settings_t;
 
 struct ma_audio_cal_settings {
@@ -237,16 +237,16 @@
          (usecase->id == USECASE_AUDIO_PLAYBACK_LOW_LATENCY) ||
          (usecase->id == USECASE_AUDIO_PLAYBACK_OFFLOAD)) &&
         /* support devices */
-        ((usecase->devices & AUDIO_DEVICE_OUT_SPEAKER) ||
-         (usecase->devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE) ||
-         (audio_is_usb_out_device(usecase->devices) &&
+        (compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_SPEAKER) ||
+         compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE) ||
+         (is_usb_out_device_type(&usecase->device_list) &&
           ma_supported_usb())))
         /* TODO: enable A2DP when it is ready */
 
         return true;
 
     ALOGV("%s: not support type %d usecase %d device %d",
-           __func__, usecase->type, usecase->id, usecase->devices);
+           __func__, usecase->type, usecase->id, get_device_types(&usecase->device_list));
 
     return false;
 }
@@ -268,7 +268,9 @@
     ma_cal->version.major = AUDIO_CAL_SETTINGS_VERSION_MAJOR_DEFAULT;
     ma_cal->version.minor = AUDIO_CAL_SETTINGS_VERSION_MINOR_DEFAULT;
     ma_cal->common.app_type = APP_TYPE_DEFAULT;
-    ma_cal->common.device = DEVICE_DEFAULT;
+    list_init(&ma_cal->common.devices);
+    update_device_list(&ma_cal->common.devices, DEVICE_DEFAULT,
+                       "", true);
     ma_cal->effect_scope_flag = EFFECTIVE_SCOPE_ALL;
 }
 
@@ -286,10 +288,10 @@
         usecase = node_to_item(node, struct audio_usecase, list);
         if (usecase->stream.out && valid_usecase(usecase)) {
             ma_cal.common.app_type = usecase->stream.out->app_type_cfg.app_type;
-            ma_cal.common.device = usecase->stream.out->devices;
+            assign_devices(&ma_cal.common.devices, &usecase->stream.out->device_list);
             ALOGV("%s: send usecase(%d) app_type(%d) device(%d)",
                       __func__, usecase->id, ma_cal.common.app_type,
-                      ma_cal.common.device);
+                      get_device_types(&ma_cal.common.devices));
 
             switch (cmd) {
                 case MA_CMD_VOL:
@@ -304,7 +306,8 @@
 
                 case MA_CMD_SWAP_ENABLE:
                     /* lr swap only enable for speaker path */
-                    if (ma_cal.common.device & AUDIO_DEVICE_OUT_SPEAKER) {
+                    if (compare_device_type(&ma_cal.common.devices,
+                                            AUDIO_DEVICE_OUT_SPEAKER)) {
                         ret = ma_set_lr_swap_l(&ma_cal, true);
                         if (ret)
                             ALOGV("ma_set_lr_swap_l enable returned with success.");
@@ -322,7 +325,8 @@
                     break;
 
                 case MA_CMD_ROTATE_ENABLE:
-                    if (ma_cal.common.device & AUDIO_DEVICE_OUT_SPEAKER) {
+                    if (compare_device_type(&ma_cal.common.devices,
+                                            AUDIO_DEVICE_OUT_SPEAKER)) {
                         ret = ma_set_orientation_l(&ma_cal, my_data->dispaly_orientation);
                         if (ret)
                             ALOGV("ma_set_orientation_l %d returned with success.",
@@ -692,16 +696,17 @@
 
     /* update audio_cal and send it */
     ma_cal.common.app_type = usecase->stream.out->app_type_cfg.app_type;
-    ma_cal.common.device = usecase->stream.out->devices;
+    assign_devices(&ma_cal.common.devices, &usecase->stream.out->device_list);
     ALOGV("%s: send usecase(%d) app_type(%d) device(%d)",
               __func__, usecase->id, ma_cal.common.app_type,
-              ma_cal.common.device);
+              get_device_types(&ma_cal.common.devices));
 
     pthread_mutex_lock(&my_data->lock);
 
     if (is_active()) {
 
-        if (ma_cal.common.device & AUDIO_DEVICE_OUT_SPEAKER) {
+        if (compare_device_type(&ma_cal.common.devices,
+                                AUDIO_DEVICE_OUT_SPEAKER)) {
             if (my_data->orientation_used)
                 ma_set_rotation_l(usecase->stream.out->dev,
                                   my_data->dispaly_orientation);
diff --git a/hal/audio_extn/passthru.c b/hal/audio_extn/passthru.c
index e900932..293ffac 100644
--- a/hal/audio_extn/passthru.c
+++ b/hal/audio_extn/passthru.c
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -244,14 +244,21 @@
  */
 bool passthru_should_drop_data(struct stream_out * out)
 {
+    uint32_t compr_passthr = 0;
     /*Drop data only
      *stream is routed to HDMI and
      *stream has PCM format or
      *if a compress offload (DSP decode) session
      */
-    if ((out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
+#ifdef AUDIO_QGKI_ENABLED
+    /* out->compr_config.codec->reserved[0] is for compr_passthr */
+    compr_passthr = out->compr_config.codec->reserved[0];
+#else
+    compr_passthr = out->compr_config.codec->compr_passthr;
+#endif
+    if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
         (((out->format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM) ||
-        ((out->compr_config.codec != NULL) && (out->compr_config.codec->compr_passthr == LEGACY_PCM)))) {
+        ((out->compr_config.codec != NULL) && (compr_passthr == LEGACY_PCM)))) {
         if (android_atomic_acquire_load(&compress_passthru_active) > 0) {
             ALOGI("drop data as pass thru is active");
             return true;
@@ -285,7 +292,7 @@
         list_for_each(node, &adev->usecase_list) {
             usecase = node_to_item(node, struct audio_usecase, list);
             if (usecase->stream.out && usecase->type == PCM_PLAYBACK &&
-                usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+                compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
                 o = usecase->stream.out;
                 temp = o->config.period_size * 1000000LL / o->sample_rate;
                 if (temp > max_period_us)
@@ -314,7 +321,7 @@
         android_atomic_dec(&compress_passthru_active);
     }
 
-    if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+    if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
         ALOGD("%s: passthru on aux digital, start keep alive", __func__);
         fp_audio_extn_keep_alive_start(KEEP_ALIVE_OUT_HDMI);
     }
@@ -461,21 +468,30 @@
         struct audio_device *adev, struct stream_out *out,
         const void *buffer __unused, size_t bytes __unused)
 {
+    uint32_t compr_passthr = 0;
+
     if(out->compr_config.codec != NULL) {
         if (passthru_is_passt_supported(adev, out)) {
             ALOGV("%s:PASSTHROUGH", __func__);
-            out->compr_config.codec->compr_passthr = PASSTHROUGH;
+            compr_passthr = PASSTHROUGH;
         } else if (passthru_is_convert_supported(adev, out)) {
             ALOGV("%s:PASSTHROUGH CONVERT", __func__);
-            out->compr_config.codec->compr_passthr = PASSTHROUGH_CONVERT;
+            compr_passthr = PASSTHROUGH_CONVERT;
         } else if (out->format == AUDIO_FORMAT_IEC61937) {
             ALOGV("%s:PASSTHROUGH IEC61937", __func__);
-            out->compr_config.codec->compr_passthr = PASSTHROUGH_IEC61937;
+            compr_passthr = PASSTHROUGH_IEC61937;
         } else {
             ALOGV("%s:NO PASSTHROUGH", __func__);
-            out->compr_config.codec->compr_passthr = LEGACY_PCM;
+            compr_passthr = LEGACY_PCM;
        }
     }
+
+#ifdef AUDIO_QGKI_ENABLED
+    /* out->compr_config.codec->reserved[0] is for compr_passthr */
+    out->compr_config.codec->reserved[0] = compr_passthr;
+#else
+    out->compr_config.codec->compr_passthr = compr_passthr;
+#endif
 }
 
 bool passthru_is_passthrough_stream(struct stream_out *out)
@@ -486,7 +502,7 @@
     }
 
     //check supported device, currently only on HDMI.
-    if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+    if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
         //passthrough flag
         if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH)
             return true;
diff --git a/hal/audio_extn/qaf.c b/hal/audio_extn/qaf.c
index 4ec524e..46e625d 100644
--- a/hal/audio_extn/qaf.c
+++ b/hal/audio_extn/qaf.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -464,7 +464,9 @@
         }
 
         if ((p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD])
-            && (p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD]->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
+            && compare_device_type(
+                   &p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD]->device_list,
+                   AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
             adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
                                      (struct audio_stream_out *)(p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD]));
             p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD] = NULL;
@@ -525,7 +527,7 @@
         config.offload_info.channel_mask = config.channel_mask = out->channel_mask;
 
         //Device is copied from the QAF passthrough input stream.
-        devices = out->devices;
+        devices = get_device_types(&out->device_list);
         flags = out->flags;
 
         ret = adev_open_output_stream((struct audio_hw_device *)p_qaf->adev,
@@ -711,7 +713,7 @@
 
     ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x)",
           __func__, &out->stream, out->usecase, use_case_table[out->usecase],
-          out->devices);
+          get_device_types(&out->device_list));
 
     if (CARD_STATUS_OFFLINE == out->card_status ||
         CARD_STATUS_OFFLINE == adev->card_status) {
@@ -781,7 +783,8 @@
         }
     }
 
-    if ((adev->is_channel_status_set == false) && (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
+    if ((adev->is_channel_status_set == false) &&
+         compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
         audio_utils_set_hdmi_channel_status(out, (char *)buffer, bytes);
         adev->is_channel_status_set = true;
     }
@@ -1637,9 +1640,9 @@
                 audio_devices_t devices;
 
                 if (qaf_mod->stream_in[QAF_IN_MAIN])
-                    devices = qaf_mod->stream_in[QAF_IN_MAIN]->devices;
+                    devices = get_device_types(&qaf_mod->stream_in[QAF_IN_MAIN]->device_list);
                 else
-                    devices = qaf_mod->stream_in[QAF_IN_PCM]->devices;
+                    devices = get_device_types(&qaf_mod->stream_in[QAF_IN_PCM]->device_list);
 
                 //If multi channel pcm or passthrough is already enabled then remove the hdmi flag from device.
                 if (p_qaf->mch_pcm_hdmi_enabled || p_qaf->passthrough_enabled) {
@@ -2348,7 +2351,7 @@
     /* Setting new device information to the mm module input streams.
      * This is needed if QAF module output streams are not created yet.
      */
-    out->devices = val;
+    reassign_device_list(&out->device_list, val, "");
 
 #ifndef A2DP_OFFLOAD_ENABLED
     if (val == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) {
diff --git a/hal/audio_extn/qap.c b/hal/audio_extn/qap.c
index 0625737..30ebe6d 100644
--- a/hal/audio_extn/qap.c
+++ b/hal/audio_extn/qap.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -431,7 +431,9 @@
         }
 
         if ((p_qap->qap_mod[i].stream_out[QAP_OUT_OFFLOAD])
-            && (p_qap->qap_mod[i].stream_out[QAP_OUT_OFFLOAD]->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
+            && compare_device_type(
+                    &p_qap->qap_mod[i].stream_out[QAP_OUT_OFFLOAD]->device_list,
+                    AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
             adev_close_output_stream((struct audio_hw_device *)p_qap->adev,
                                      (struct audio_stream_out *)(p_qap->qap_mod[i].stream_out[QAP_OUT_OFFLOAD]));
             p_qap->qap_mod[i].stream_out[QAP_OUT_OFFLOAD] = NULL;
@@ -492,7 +494,7 @@
         config.offload_info.channel_mask = config.channel_mask = out->channel_mask;
 
         //Device is copied from the QAP passthrough input stream.
-        devices = out->devices;
+        devices = get_device_types(&out->device_list);
         flags = out->flags;
 
         ret = adev_open_output_stream((struct audio_hw_device *)p_qap->adev,
@@ -870,7 +872,7 @@
 
     ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x)",
           __func__, &out->stream, out->usecase, use_case_table[out->usecase],
-          out->devices);
+          get_device_types(&out->device_list));
 
     if (CARD_STATUS_OFFLINE == out->card_status ||
         CARD_STATUS_OFFLINE == adev->card_status) {
@@ -959,7 +961,8 @@
         }
     }
 
-    if ((adev->is_channel_status_set == false) && (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
+    if ((adev->is_channel_status_set == false) &&
+         compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
         audio_utils_set_hdmi_channel_status(out, (char *)buffer, bytes);
         adev->is_channel_status_set = true;
     }
@@ -1759,9 +1762,9 @@
                 audio_devices_t devices;
 
                 if (qap_mod->stream_in[QAP_IN_MAIN])
-                    devices = qap_mod->stream_in[QAP_IN_MAIN]->devices;
+                    devices = get_device_types(&qap_mod->stream_in[QAP_IN_MAIN]->device_list);
                 else
-                    devices = qap_mod->stream_in[QAP_IN_PCM]->devices;
+                    devices = get_device_types(&qap_mod->stream_in[QAP_IN_PCM]->device_list);
 
                 //If multi channel pcm or passthrough is already enabled then remove the hdmi flag from device.
                 if (p_qap->mch_pcm_hdmi_enabled || p_qap->passthrough_enabled) {
@@ -2595,6 +2598,7 @@
     int ret = 0;
     int err = 0;
     struct qap_module *qap_mod = NULL;
+    char *address = "";
 
     DEBUG_MSG("usecase(%d: %s) kvpairs: %s", out->usecase, use_case_table[out->usecase], kvpairs);
 
@@ -2612,7 +2616,7 @@
     /* Setting new device information to the mm module input streams.
      * This is needed if QAP module output streams are not created yet.
      */
-    out->devices = val;
+    reassign_device_list(&out->device_list, val, address);
 
 #ifndef SPLIT_A2DP_ENABLED
     if (val == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) {
diff --git a/hal/audio_extn/soundtrigger.c b/hal/audio_extn/soundtrigger.c
index a175b83..4ef3581 100644
--- a/hal/audio_extn/soundtrigger.c
+++ b/hal/audio_extn/soundtrigger.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, 2016-2019 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 2016-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -53,9 +53,8 @@
 #define MINOR_VERSION(ver) ((ver) & 0x00ff)
 
 /* Proprietary interface version used for compatibility with STHAL */
-#define STHAL_PROP_API_VERSION_1_0 MAKE_HAL_VERSION(1, 0)
-#define STHAL_PROP_API_VERSION_1_1 MAKE_HAL_VERSION(1, 1)
-#define STHAL_PROP_API_CURRENT_VERSION STHAL_PROP_API_VERSION_1_1
+#define STHAL_PROP_API_VERSION_2_0 MAKE_HAL_VERSION(2, 0)
+#define STHAL_PROP_API_CURRENT_VERSION STHAL_PROP_API_VERSION_2_0
 
 #define ST_EVENT_CONFIG_MAX_STR_VALUE 32
 #define ST_DEVICE_HANDSET_MIC 1
@@ -129,7 +128,7 @@
 typedef struct sound_trigger_event_info sound_trigger_event_info_t;
 
 struct sound_trigger_device_info {
-    int device;
+    struct listnode devices;
 };
 
 struct sound_trigger_get_param_data {
@@ -571,7 +570,7 @@
     struct audio_event_info ev_info;
     audio_event_type_t ev;
     /*Initialize to invalid device*/
-    ev_info.device_info.device = -1;
+    list_init(&ev_info.device_info.devices);
 
     if (!st_dev)
        return;
@@ -581,14 +580,10 @@
         return;
     }
 
-    if ((st_dev->sthal_prop_api_version < STHAL_PROP_API_VERSION_1_0) &&
-        (uc_info->type != PCM_PLAYBACK))
-        return;
-
     if ((uc_info->in_snd_device >= SND_DEVICE_IN_BEGIN &&
         uc_info->in_snd_device < SND_DEVICE_IN_END)) {
         if (is_same_as_st_device(uc_info->in_snd_device))
-            ev_info.device_info.device = ST_DEVICE_HANDSET_MIC;
+            update_device_list(&ev_info.device_info.devices, ST_DEVICE_HANDSET_MIC, "", true);
     } else {
         ALOGE("%s: invalid input device 0x%x, for event %d",
                     __func__, uc_info->in_snd_device, event);
@@ -599,9 +594,10 @@
     if (raise_event) {
         if (uc_info->type == PCM_PLAYBACK) {
             if (uc_info->stream.out)
-                ev_info.device_info.device = uc_info->stream.out->devices;
+                assign_devices(&ev_info.device_info.devices, &uc_info->stream.out->device_list);
             else
-                ev_info.device_info.device = AUDIO_DEVICE_OUT_SPEAKER;
+                reassign_device_list(&ev_info.device_info.devices,
+                                     AUDIO_DEVICE_OUT_SPEAKER, "");
             switch(event) {
             case ST_EVENT_STREAM_FREE:
                 st_dev->st_callback(AUDIO_EVENT_PLAYBACK_STREAM_INACTIVE, &ev_info);
@@ -629,9 +625,9 @@
 
 void audio_extn_sound_trigger_update_battery_status(bool charging)
 {
-    struct audio_event_info ev_info;
+    struct audio_event_info ev_info = {{0}, {0}};
 
-    if (!st_dev || st_dev->sthal_prop_api_version < STHAL_PROP_API_VERSION_1_0)
+    if (!st_dev)
         return;
 
     ev_info.u.value = charging;
diff --git a/hal/audio_extn/source_track.c b/hal/audio_extn/source_track.c
index 064fad8..9705d55 100644
--- a/hal/audio_extn/source_track.c
+++ b/hal/audio_extn/source_track.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -230,7 +230,7 @@
 
     if (usecase && (usecase->id != USECASE_AUDIO_SPKR_CALIB_TX)) {
         if (is_stt_supported_snd_device(usecase->in_snd_device)) {
-             in_device = get_input_audio_device(usecase->devices);
+             in_device = get_input_audio_device(get_device_types(&usecase->device_list));
              ret = add_audio_intf_name_to_mixer_ctl(in_device, mixer_ctl_name,
                 audio_device_to_interface_table, audio_device_to_interface_table_len);
         } else {
diff --git a/hal/audio_extn/ssr.c b/hal/audio_extn/ssr.c
index d83b508..8cb7b4e 100644
--- a/hal/audio_extn/ssr.c
+++ b/hal/audio_extn/ssr.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2018, 2020, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -339,7 +339,7 @@
 bool  ssr_check_usecase(struct stream_in *in) {
     int ret = false;
     int channel_count = audio_channel_count_from_in_mask(in->channel_mask);
-    audio_devices_t devices = in->device;
+    audio_devices_t devices = get_device_types(&in->device_list);
     audio_source_t source = in->source;
 
     if ((ssr_get_enabled()) &&
diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c
index a2d559d..531c4b2 100644
--- a/hal/audio_extn/usb.c
+++ b/hal/audio_extn/usb.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013, 2016-2020, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -1472,7 +1472,7 @@
         list_for_each(node, &adev->usecase_list) {
             usecase = node_to_item(node, struct audio_usecase, list);
             if (usecase->type == PCM_PLAYBACK &&
-                audio_is_usb_out_device(usecase->devices & AUDIO_DEVICE_OUT_ALL_USB )) {
+                is_usb_out_device_type(&usecase->device_list)) {
                 switch (usecase->id) {
                     case USECASE_AUDIO_PLAYBACK_MMAP:
                     case USECASE_AUDIO_PLAYBACK_ULL:
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 92887f0..e56fee3 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -672,7 +672,7 @@
 
 void audio_extn_utils_update_stream_input_app_type_cfg(void *platform,
                                   struct listnode *streams_input_cfg_list,
-                                  audio_devices_t devices __unused,
+                                  struct listnode *devices __unused,
                                   audio_input_flags_t flags,
                                   audio_format_t format,
                                   uint32_t sample_rate,
@@ -710,7 +710,7 @@
 
 void audio_extn_utils_update_stream_output_app_type_cfg(void *platform,
                                   struct listnode *streams_output_cfg_list,
-                                  audio_devices_t devices,
+                                  struct listnode *devices,
                                   audio_output_flags_t flags,
                                   audio_format_t format,
                                   uint32_t sample_rate,
@@ -724,7 +724,7 @@
     struct stream_format *sf_info;
     char value[PROPERTY_VALUE_MAX] = {0};
 
-    if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
+    if (compare_device_type(devices, AUDIO_DEVICE_OUT_SPEAKER)) {
         int bw = platform_get_snd_device_bit_width(SND_DEVICE_OUT_SPEAKER);
         if ((-ENOSYS != bw) && (bit_width > (uint32_t)bw))
             bit_width = (uint32_t)bw;
@@ -866,7 +866,7 @@
     case PCM_PLAYBACK:
         audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
                                                 &adev->streams_output_cfg_list,
-                                                usecase->stream.out->devices,
+                                                &usecase->stream.out->device_list,
                                                 usecase->stream.out->flags,
                                                 usecase->stream.out->hal_op_format,
                                                 usecase->stream.out->sample_rate,
@@ -882,7 +882,7 @@
         else
             audio_extn_utils_update_stream_input_app_type_cfg(adev->platform,
                                                 &adev->streams_input_cfg_list,
-                                                usecase->stream.in->device,
+                                                &usecase->stream.in->device_list,
                                                 usecase->stream.in->flags,
                                                 usecase->stream.in->format,
                                                 usecase->stream.in->sample_rate,
@@ -894,7 +894,7 @@
     case TRANSCODE_LOOPBACK_RX :
         audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
                                                 &adev->streams_output_cfg_list,
-                                                usecase->stream.inout->out_config.devices,
+                                                &usecase->stream.inout->out_config.device_list,
                                                 0,
                                                 usecase->stream.inout->out_config.format,
                                                 usecase->stream.inout->out_config.sample_rate,
@@ -1012,7 +1012,7 @@
         goto exit_send_app_type_cfg;
     }
 
-    if (usecase->devices & AUDIO_DEVICE_OUT_BUS)
+    if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS))
         is_bus_dev_usecase = true;
 
     snd_device = usecase->out_snd_device;
@@ -1118,7 +1118,8 @@
 
         if (usecase->id == USECASE_AUDIO_PLAYBACK_VOIP) {
             usecase->stream.out->app_type_cfg.sample_rate = usecase->stream.out->sample_rate;
-        } else if (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
+        } else if (compare_device_type(&usecase->stream.out->device_list,
+                                       AUDIO_DEVICE_OUT_SPEAKER)) {
             usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
         } else if ((snd_device == SND_DEVICE_OUT_HDMI ||
                     snd_device == SND_DEVICE_OUT_USB_HEADSET ||
@@ -1138,7 +1139,7 @@
             (usecase->stream.out->sample_rate < OUTPUT_SAMPLING_RATE_44100)) {
             /* Reset to default if no native stream is active*/
             usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
-        } else if (usecase->stream.out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
+        } else if (is_a2dp_out_device_type(&usecase->stream.out->device_list)) {
                  /*
                   * For a2dp playback get encoder sampling rate and set copp sampling rate,
                   * for bit width use the stream param only.
@@ -2101,7 +2102,7 @@
         backend = platform_get_snd_device_backend_interface(usecase->out_snd_device);
         if (!backend) {
             ALOGE("%s: Unsupported device %d", __func__,
-                   usecase->stream.out->devices);
+                   get_device_types(&usecase->stream.out->device_list));
             ret = -EINVAL;
             goto done;
         }
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index f70883d..58bbfb5 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -660,7 +660,7 @@
                                                   uint32_t *dsp_frames) {
     // Adjustment accounts for A2dp encoder latency with offload usecases
     // Note: Encoder latency is returned in ms.
-    if (AUDIO_DEVICE_OUT_ALL_A2DP & out->devices) {
+    if (is_a2dp_out_device_type(&out->device_list)) {
         unsigned long offset =
                 (audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000);
         *dsp_frames = (*dsp_frames > offset) ? (*dsp_frames - offset) : 0;
@@ -682,23 +682,20 @@
     }
 }
 
-static inline void patch_map_remove(struct audio_device *adev,
+static inline void patch_map_remove_l(struct audio_device *adev,
                                 audio_patch_handle_t patch_handle)
 {
     if (patch_handle == AUDIO_PATCH_HANDLE_NONE)
         return;
 
-    pthread_mutex_lock(&adev->lock);
     struct audio_patch_info *p_info =
         hashmapGet(adev->patch_map, (void *) (intptr_t) patch_handle);
     if (p_info) {
         ALOGV("%s: Remove patch %d", __func__, patch_handle);
         hashmapRemove(adev->patch_map, (void *) (intptr_t) patch_handle);
         free(p_info->patch);
-        pthread_mutex_destroy(&p_info->lock);
         free(p_info);
     }
-    pthread_mutex_unlock(&adev->lock);
 }
 
 static inline int io_streams_map_insert(struct audio_device *adev,
@@ -715,14 +712,13 @@
     }
     s_info->stream = stream;
     s_info->patch_handle = patch_handle;
-    pthread_mutex_init(&s_info->lock, (const pthread_mutexattr_t *) NULL);
 
     pthread_mutex_lock(&adev->lock);
     struct audio_stream_info *stream_info =
             hashmapPut(adev->io_streams_map, (void *) (intptr_t) handle, (void *) s_info);
-    pthread_mutex_unlock(&adev->lock);
     if (stream_info != NULL)
         free(stream_info);
+    pthread_mutex_unlock(&adev->lock);
     ALOGD("%s: Added stream in io_streams_map with handle %d", __func__, handle);
     return 0;
 }
@@ -733,24 +729,22 @@
     pthread_mutex_lock(&adev->lock);
     struct audio_stream_info *s_info =
             hashmapRemove(adev->io_streams_map, (void *) (intptr_t) handle);
-    pthread_mutex_unlock(&adev->lock);
     if (s_info == NULL)
-        return;
+        goto done;
     ALOGD("%s: Removed stream with handle %d", __func__, handle);
-    patch_map_remove(adev, s_info->patch_handle);
-    pthread_mutex_destroy(&s_info->lock);
+    patch_map_remove_l(adev, s_info->patch_handle);
     free(s_info);
+done:
+    pthread_mutex_unlock(&adev->lock);
     return;
 }
 
-static struct audio_patch_info* fetch_patch_info(struct audio_device *adev,
+static struct audio_patch_info* fetch_patch_info_l(struct audio_device *adev,
                                     audio_patch_handle_t handle)
 {
     struct audio_patch_info *p_info = NULL;
-    pthread_mutex_lock(&adev->lock);
     p_info = (struct audio_patch_info *)
                  hashmapGet(adev->patch_map, (void *) (intptr_t) handle);
-    pthread_mutex_unlock(&adev->lock);
     return p_info;
 }
 
@@ -1182,6 +1176,7 @@
     char mixer_path[MIXER_PATH_MAX_LENGTH];
     struct stream_out *out = NULL;
     struct stream_in *in = NULL;
+    struct listnode out_devices;
     int ret = 0;
 
     if (usecase == NULL)
@@ -1196,25 +1191,30 @@
 
         if (in) {
             if (in->enable_aec || in->enable_ec_port) {
-                audio_devices_t out_device = AUDIO_DEVICE_OUT_SPEAKER;
+                list_init(&out_devices);
+                update_device_list(&out_devices, AUDIO_DEVICE_OUT_SPEAKER, "", true);
                 struct listnode *node;
                 struct audio_usecase *voip_usecase = get_usecase_from_list(adev,
                                                            USECASE_AUDIO_PLAYBACK_VOIP);
                 if (voip_usecase) {
-                    out_device = voip_usecase->stream.out->devices;
+                    assign_devices(&out_devices,
+                                   &voip_usecase->stream.out->device_list);
                 } else if (adev->primary_output &&
                               !adev->primary_output->standby) {
-                    out_device = adev->primary_output->devices;
+                    assign_devices(&out_devices,
+                                   &adev->primary_output->device_list);
                 } else {
                     list_for_each(node, &adev->usecase_list) {
                         uinfo = node_to_item(node, struct audio_usecase, list);
                         if (uinfo->type != PCM_CAPTURE) {
-                            out_device = uinfo->stream.out->devices;
+                            assign_devices(&out_devices,
+                                           &uinfo->stream.out->device_list);
                             break;
                         }
                     }
                 }
-                platform_set_echo_reference(adev, true, out_device);
+
+                platform_set_echo_reference(adev, true, &out_devices);
                 in->ec_opened = true;
             }
         }
@@ -1245,7 +1245,7 @@
 
     if (usecase->type == PCM_CAPTURE) {
         in = usecase->stream.in;
-        if (in && is_loopback_input_device(in->device)) {
+        if (in && is_loopback_input_device(get_device_types(&in->device_list))) {
             ALOGD("%s: set custom mtmx params v1", __func__);
             audio_extn_set_custom_mtmx_params_v1(adev, usecase, true);
         }
@@ -1296,7 +1296,9 @@
     if (usecase->type == PCM_CAPTURE) {
         struct stream_in *in = usecase->stream.in;
         if (in && in->ec_opened) {
-            platform_set_echo_reference(in->dev, false, AUDIO_DEVICE_NONE);
+            struct listnode out_devices;
+            list_init(&out_devices);
+            platform_set_echo_reference(in->dev, false, &out_devices);
             in->ec_opened = false;
         }
     }
@@ -1305,7 +1307,7 @@
 
     if (usecase->type == PCM_CAPTURE) {
         in = usecase->stream.in;
-        if (in && is_loopback_input_device(in->device)) {
+        if (in && is_loopback_input_device(get_device_types(&in->device_list))) {
             ALOGD("%s: reset custom mtmx params v1", __func__);
             audio_extn_set_custom_mtmx_params_v1(adev, usecase, false);
         }
@@ -1598,35 +1600,39 @@
                                                struct audio_usecase *new_uc,
                                                snd_device_t new_snd_device)
 {
-    audio_devices_t a1, a2;
+    struct listnode a1, a2;
 
     snd_device_t d1 = uc->out_snd_device;
     snd_device_t d2 = new_snd_device;
 
+    list_init(&a1);
+    list_init(&a2);
+
     switch (uc->type) {
         case TRANSCODE_LOOPBACK_RX :
-            a1 = uc->stream.inout->out_config.devices;
-            a2 = new_uc->stream.inout->out_config.devices;
+            assign_devices(&a1, &uc->stream.inout->out_config.device_list);
+            assign_devices(&a2, &new_uc->stream.inout->out_config.device_list);
             break;
         default :
-            a1 = uc->stream.out->devices;
-            a2 = new_uc->stream.out->devices;
+            assign_devices(&a1, &uc->stream.out->device_list);
+            assign_devices(&a2, &new_uc->stream.out->device_list);
             break;
     }
 
     // Treat as a special case when a1 and a2 are not disjoint
-    if ((a1 != a2) && (a1 & a2)) {
+    if (!compare_devices(&a1, &a2) &&
+         compare_devices_for_any_match(&a1 ,&a2)) {
         snd_device_t d3[2];
         int num_devices = 0;
         int ret = platform_split_snd_device(platform,
-                                            popcount(a1) > 1 ? d1 : d2,
+                                            list_length(&a1) > 1 ? d1 : d2,
                                             &num_devices,
                                             d3);
         if (ret < 0) {
             if (ret != -ENOSYS) {
                 ALOGW("%s failed to split snd_device %d",
                       __func__,
-                      popcount(a1) > 1 ? d1 : d2);
+                      list_length(&a1) > 1 ? d1 : d2);
             }
             goto end;
         }
@@ -1634,7 +1640,7 @@
         if (platform_check_backends_match(d3[0], d3[1])) {
             return d2; // case 5
         } else {
-            if (popcount(a1) > 1)
+            if (list_length(&a1) > 1)
                 return d1; //case 7
             // check if d1 is related to any of d3's
             if (d1 == d3[0] || d1 == d3[1])
@@ -1716,12 +1722,12 @@
             uc_derive_snd_device = derive_playback_snd_device(adev->platform,
                                                usecase, uc_info, snd_device);
             if (((uc_derive_snd_device != usecase->out_snd_device) || force_routing) &&
-                ((usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) ||
-                (usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) ||
-                (usecase->devices & AUDIO_DEVICE_OUT_USB_DEVICE) ||
-                (usecase->devices &  AUDIO_DEVICE_OUT_USB_HEADSET) ||
-                (usecase->devices & AUDIO_DEVICE_OUT_ALL_A2DP) ||
-                (usecase->devices & AUDIO_DEVICE_OUT_ALL_SCO)) &&
+                (is_codec_backend_out_device_type(&usecase->device_list) ||
+                compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) ||
+                compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_USB_DEVICE) ||
+                compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_USB_HEADSET) ||
+                is_a2dp_out_device_type(&usecase->device_list) ||
+                is_sco_out_device_type(&usecase->device_list)) &&
                 ((force_restart_session) ||
                 (platform_check_backends_match(snd_device, usecase->out_snd_device)))) {
                 ALOGD("%s:becf: check_usecases (%s) is active on (%s) - disabling ..",
@@ -1803,7 +1809,7 @@
                                                            usecase->out_snd_device,
                                                            platform_get_input_snd_device(
                                                                adev->platform, NULL,
-                                                               uc_info->devices));
+                                                               &uc_info->device_list));
                     enable_audio_route(adev, usecase);
                     if (usecase->stream.out && usecase->id == USECASE_AUDIO_PLAYBACK_VOIP) {
                         out_set_voip_volume(&usecase->stream.out->stream,
@@ -1824,7 +1830,7 @@
     struct audio_usecase *usecase;
     bool switch_device[AUDIO_USECASE_MAX];
     int i, num_uc_to_switch = 0;
-    int backend_check_cond = AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND;
+    int backend_check_cond = is_codec_backend_out_device_type(&uc_info->device_list);
     int status = 0;
 
     bool force_routing = platform_check_and_set_capture_codec_backend_cfg(adev, uc_info,
@@ -1837,7 +1843,7 @@
      * codec backend or vice versa causes issues.
      */
     if (uc_info->type == PCM_CAPTURE)
-        backend_check_cond = AUDIO_DEVICE_IN_ALL_CODEC_BACKEND;
+        backend_check_cond = is_codec_backend_in_device_type(&uc_info->device_list);
     /*
      * This function is to make sure that all the active capture usecases
      * are always routed to the same input sound device.
@@ -1859,13 +1865,14 @@
         if (usecase->type != PCM_PLAYBACK &&
                 usecase != uc_info &&
                 (usecase->in_snd_device != snd_device || force_routing) &&
-                ((uc_info->devices & backend_check_cond) &&
-                 (((usecase->devices & ~AUDIO_DEVICE_BIT_IN) & AUDIO_DEVICE_IN_ALL_CODEC_BACKEND) ||
+                ((backend_check_cond &&
+                 (is_codec_backend_in_device_type(&usecase->device_list) ||
                   (usecase->type == VOIP_CALL))) &&
                 ((uc_info->type == VOICE_CALL &&
-                  usecase->devices == AUDIO_DEVICE_IN_VOICE_CALL) ||
+                 is_single_device_type_equal(&usecase->device_list,
+                                            AUDIO_DEVICE_IN_VOICE_CALL)) ||
                  platform_check_backends_match(snd_device,\
-                                              usecase->in_snd_device)) &&
+                                              usecase->in_snd_device))) &&
                 (usecase->id != USECASE_AUDIO_SPKR_CALIB_TX)) {
             ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
                   __func__, use_case_table[usecase->id],
@@ -2334,8 +2341,8 @@
 
     if (is_offload_usecase(usecase->id) &&
         (usecase->stream.out->sample_rate == OUTPUT_SAMPLING_RATE_44100) &&
-        (usecase->stream.out->devices == AUDIO_DEVICE_OUT_WIRED_HEADSET ||
-         usecase->stream.out->devices == AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+        (compare_device_type(&usecase->stream.out->device_list, AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+         compare_device_type(&usecase->stream.out->device_list, AUDIO_DEVICE_OUT_WIRED_HEADPHONE))) {
         is_it_true_mode = (NATIVE_AUDIO_MODE_TRUE_44_1 == platform_get_native_support()? true : false);
          if ((is_it_true_mode && !adev->native_playback_enabled) ||
              (!is_it_true_mode && adev->native_playback_enabled)){
@@ -2347,7 +2354,7 @@
     // Force all a2dp output devices to reconfigure for proper AFE encode format
     //Also handle a case where in earlier a2dp start failed as A2DP stream was
     //in suspended state, hence try to trigger a retry when we again get a routing request.
-    if((usecase->stream.out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) &&
+    if(is_a2dp_out_device_type(&usecase->stream.out->device_list) &&
         audio_extn_a2dp_is_force_device_switch()) {
          ALOGD("Force a2dp device switch to update new encoder config");
          ret = true;
@@ -2571,7 +2578,7 @@
             ALOGE("%s: stream.out is NULL", __func__);
             return -EINVAL;
         }
-        if (usecase->devices & AUDIO_DEVICE_OUT_BUS) {
+        if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS)) {
             out_snd_device = audio_extn_auto_hal_get_output_snd_device(adev,
                                                                        uc_id);
             in_snd_device = audio_extn_auto_hal_get_input_snd_device(adev,
@@ -2581,28 +2588,30 @@
                                                             usecase->stream.out);
             in_snd_device = platform_get_input_snd_device(adev->platform,
                                                           NULL,
-                                                          usecase->stream.out->devices);
+                                                          &usecase->stream.out->device_list);
         }
-        usecase->devices = usecase->stream.out->devices;
+        assign_devices(&usecase->device_list, &usecase->stream.out->device_list);
     } else if (usecase->type == TRANSCODE_LOOPBACK_RX) {
         if (usecase->stream.inout == NULL) {
             ALOGE("%s: stream.inout is NULL", __func__);
             return -EINVAL;
         }
-        stream_out.devices = usecase->stream.inout->out_config.devices;
+        assign_devices(&stream_out.device_list, &usecase->stream.inout->out_config.device_list);
         stream_out.sample_rate = usecase->stream.inout->out_config.sample_rate;
         stream_out.format = usecase->stream.inout->out_config.format;
         stream_out.channel_mask = usecase->stream.inout->out_config.channel_mask;
         out_snd_device = platform_get_output_snd_device(adev->platform,
                                                         &stream_out);
-        usecase->devices = out_snd_device;
+        assign_devices(&usecase->device_list,
+                       &usecase->stream.inout->out_config.device_list);
     } else if (usecase->type == TRANSCODE_LOOPBACK_TX ) {
         if (usecase->stream.inout == NULL) {
             ALOGE("%s: stream.inout is NULL", __func__);
             return -EINVAL;
         }
-        in_snd_device = platform_get_input_snd_device(adev->platform, NULL, AUDIO_DEVICE_NONE);
-        usecase->devices = in_snd_device;
+        in_snd_device = platform_get_input_snd_device(adev->platform, NULL, NULL);
+        assign_devices(&usecase->device_list,
+                       &usecase->stream.inout->in_config.device_list);
     } else {
         /*
          * If the voice call is active, use the sound devices of voice call usecase
@@ -2616,12 +2625,14 @@
         if (voice_is_in_call(adev) && adev->mode != AUDIO_MODE_NORMAL) {
             vc_usecase = get_usecase_from_list(adev,
                                                get_usecase_id_from_usecase_type(adev, VOICE_CALL));
-            if ((vc_usecase) && (((vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) &&
-                                 (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND)) ||
-                                 ((vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) &&
-                                 (usecase->devices & AUDIO_DEVICE_IN_ALL_CODEC_BACKEND)) ||
-                                 (vc_usecase->devices == AUDIO_DEVICE_OUT_HEARING_AID) ||
-                                 (usecase->devices == AUDIO_DEVICE_IN_VOICE_CALL))) {
+            if ((vc_usecase) && ((is_codec_backend_out_device_type(&vc_usecase->device_list) &&
+                                 is_codec_backend_out_device_type(&usecase->device_list)) ||
+                                 (is_codec_backend_out_device_type(&vc_usecase->device_list) &&
+                                 is_codec_backend_in_device_type(&usecase->device_list)) ||
+                                 is_single_device_type_equal(&vc_usecase->device_list,
+                                                        AUDIO_DEVICE_OUT_HEARING_AID) ||
+                                 is_single_device_type_equal(&usecase->device_list,
+                                                     AUDIO_DEVICE_IN_VOICE_CALL))) {
                 in_snd_device = vc_usecase->in_snd_device;
                 out_snd_device = vc_usecase->out_snd_device;
             }
@@ -2637,9 +2648,9 @@
                                                        adev->platform,
                                                        usecase->stream.out));
             }
-            if ((voip_usecase) && ((voip_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) &&
-                ((usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) ||
-                  ((usecase->devices & ~AUDIO_DEVICE_BIT_IN) & AUDIO_DEVICE_IN_ALL_CODEC_BACKEND)) &&
+            if ((voip_usecase) && (is_codec_backend_out_device_type(&voip_usecase->device_list) &&
+                (is_codec_backend_out_device_type(&usecase->device_list) ||
+                 is_codec_backend_in_device_type(&usecase->device_list)) &&
                 out_snd_device_backend_match &&
                  (voip_usecase->stream.out != adev->primary_output))) {
                     in_snd_device = voip_usecase->in_snd_device;
@@ -2648,7 +2659,7 @@
         } else if (audio_extn_hfp_is_active(adev)) {
             hfp_ucid = audio_extn_hfp_get_usecase();
             hfp_usecase = get_usecase_from_list(adev, hfp_ucid);
-            if ((hfp_usecase) && (hfp_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND)) {
+            if ((hfp_usecase) && is_codec_backend_out_device_type(&hfp_usecase->device_list)) {
                    in_snd_device = hfp_usecase->in_snd_device;
                    out_snd_device = hfp_usecase->out_snd_device;
             }
@@ -2658,12 +2669,12 @@
                 ALOGE("%s: stream.out is NULL", __func__);
                 return -EINVAL;
             }
-            usecase->devices = usecase->stream.out->devices;
+            assign_devices(&usecase->device_list, &usecase->stream.out->device_list);
             in_snd_device = SND_DEVICE_NONE;
             if (out_snd_device == SND_DEVICE_NONE) {
                 struct stream_out *voip_out = adev->primary_output;
                 struct stream_in *voip_in = get_voice_communication_input(adev);
-                if (usecase->devices & AUDIO_DEVICE_OUT_BUS)
+                if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS))
                     out_snd_device = audio_extn_auto_hal_get_output_snd_device(adev, uc_id);
                 else
                     out_snd_device = platform_get_output_snd_device(adev->platform,
@@ -2681,13 +2692,14 @@
                 ALOGE("%s: stream.in is NULL", __func__);
                 return -EINVAL;
             }
-            usecase->devices = usecase->stream.in->device;
+            assign_devices(&usecase->device_list, &usecase->stream.in->device_list);
             out_snd_device = SND_DEVICE_NONE;
             if (in_snd_device == SND_DEVICE_NONE) {
-                audio_devices_t out_device = AUDIO_DEVICE_NONE;
+                struct listnode out_devices;
                 struct stream_in *voip_in = get_voice_communication_input(adev);
                 struct stream_in *priority_in = NULL;
 
+                list_init(&out_devices);
                 if (voip_in != NULL) {
                     struct audio_usecase *voip_usecase = get_usecase_from_list(adev,
                                                              USECASE_AUDIO_PLAYBACK_VOIP);
@@ -2695,16 +2707,16 @@
                     usecase->stream.in->enable_ec_port = false;
 
                     if (usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY) {
-                        out_device = AUDIO_DEVICE_OUT_TELEPHONY_TX;
+                        reassign_device_list(&out_devices, AUDIO_DEVICE_OUT_TELEPHONY_TX, "");
                     } else if (voip_usecase) {
-                        out_device = voip_usecase->stream.out->devices;
+                        assign_devices(&out_devices, &voip_usecase->stream.out->device_list);
                     } else if (adev->primary_output &&
                                   !adev->primary_output->standby) {
-                        out_device = adev->primary_output->devices;
+                        assign_devices(&out_devices, &adev->primary_output->device_list);
                     } else {
                         /* forcing speaker o/p device to get matching i/p pair
                            in case o/p is not routed from same primary HAL */
-                        out_device = AUDIO_DEVICE_OUT_SPEAKER;
+                        reassign_device_list(&out_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
                     }
                     priority_in = voip_in;
                 } else {
@@ -2717,7 +2729,7 @@
 
                 in_snd_device = platform_get_input_snd_device(adev->platform,
                                                               priority_in,
-                                                              out_device);
+                                                              &out_devices);
             }
         }
     }
@@ -2729,9 +2741,9 @@
             return 0;
     }
 
-    if (!(usecase->devices & AUDIO_DEVICE_OUT_BUS) &&
+    if (!compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS) &&
         ((is_btsco_device(out_snd_device,in_snd_device) && !adev->bt_sco_on) ||
-            (is_a2dp_device(out_snd_device) && !audio_extn_a2dp_source_is_ready()))) {
+         (is_a2dp_device(out_snd_device) && !audio_extn_a2dp_source_is_ready()))) {
         ALOGD("SCO/A2DP is selected but they are not connected/ready hence dont route");
         return 0;
     }
@@ -2852,7 +2864,7 @@
                                                             usecase);
     if (usecase->type == PCM_PLAYBACK) {
         if ((24 == usecase->stream.out->bit_width) &&
-                (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER)) {
+                compare_device_type(&usecase->stream.out->device_list, AUDIO_DEVICE_OUT_SPEAKER)) {
             usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
         } else if ((out_snd_device == SND_DEVICE_OUT_HDMI ||
                     out_snd_device == SND_DEVICE_OUT_USB_HEADSET ||
@@ -2982,7 +2994,7 @@
     /* 2. Disable the tx device */
     disable_snd_device(adev, uc_info->in_snd_device);
 
-    if (is_loopback_input_device(in->device))
+    if (is_loopback_input_device(get_device_types(&in->device_list)))
         audio_extn_keep_alive_stop(KEEP_ALIVE_OUT_PRIMARY);
 
     list_remove(&uc_info->list);
@@ -3026,7 +3038,7 @@
         goto error_config;
     }
 
-    if (audio_is_bluetooth_sco_device(in->device)) {
+    if (is_sco_in_device_type(&in->device_list)) {
         if (!adev->bt_sco_on) {
             ALOGE("%s: SCO profile is not ready, return error", __func__);
             ret = -EIO;
@@ -3065,7 +3077,8 @@
     uc_info->id = in->usecase;
     uc_info->type = PCM_CAPTURE;
     uc_info->stream.in = in;
-    uc_info->devices = in->device;
+    list_init(&uc_info->device_list);
+    assign_devices(&uc_info->device_list, &in->device_list);
     uc_info->in_snd_device = SND_DEVICE_NONE;
     uc_info->out_snd_device = SND_DEVICE_NONE;
 
@@ -3175,7 +3188,7 @@
     audio_extn_audiozoom_set_microphone_direction(in, in->zoom);
     audio_extn_audiozoom_set_microphone_field_dimension(in, in->direction);
 
-    if (is_loopback_input_device(in->device))
+    if (is_loopback_input_device(get_device_types(&in->device_list)))
         audio_extn_keep_alive_start(KEEP_ALIVE_OUT_PRIMARY);
 
 done_open:
@@ -3556,7 +3569,7 @@
                                                 adev->dsp_bit_width_enforce_mode,
                                                 false);
     }
-    if (audio_is_usb_out_device(out->devices & AUDIO_DEVICE_OUT_ALL_USB)) {
+    if (is_usb_out_device_type(&out->device_list)) {
         ret = audio_extn_usb_check_and_set_svc_int(uc_info,
                                                    false);
 
@@ -3573,13 +3586,18 @@
         (audio_extn_passthru_is_passthrough_stream(out))) {
         ALOGV("Disable passthrough , reset mixer to pcm");
         /* NO_PASSTHROUGH */
+#ifdef AUDIO_GKI_ENABLED
+        /* out->compr_config.codec->reserved[0] is for compr_passthr */
+        out->compr_config.codec->reserved[0] = 0;
+#else
         out->compr_config.codec->compr_passthr = 0;
+#endif
         audio_extn_passthru_on_stop(out);
         audio_extn_dolby_set_dap_bypass(adev, DAP_STATE_ON);
     }
 
     /* Must be called after removing the usecase from list */
-    if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
+    if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL))
         audio_extn_keep_alive_start(KEEP_ALIVE_OUT_HDMI);
 
     if (out->ip_hdlr_handle) {
@@ -3593,7 +3611,7 @@
        2) trigger voip input to reroute when voip output changes to
           hearing aid. */
     if (has_voip_usecase ||
-            out->devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
+            compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
         struct listnode *node;
         struct audio_usecase *usecase;
         list_for_each(node, &adev->usecase_list) {
@@ -3670,7 +3688,12 @@
 
     ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x) is_haptic_usecase(%d)",
           __func__, &out->stream, out->usecase, use_case_table[out->usecase],
-          out->devices, is_haptic_usecase);
+          get_device_types(&out->device_list), is_haptic_usecase);
+
+    bool is_speaker_active = compare_device_type(&out->device_list,
+                                                 AUDIO_DEVICE_OUT_SPEAKER);
+    bool is_speaker_safe_active = compare_device_type(&out->device_list,
+                                                      AUDIO_DEVICE_OUT_SPEAKER_SAFE);
 
     if (CARD_STATUS_OFFLINE == out->card_status ||
         CARD_STATUS_OFFLINE == adev->card_status) {
@@ -3689,10 +3712,9 @@
         }
     }
 
-    if (out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
+    if (is_a2dp_out_device_type(&out->device_list)) {
         if (!audio_extn_a2dp_source_is_ready()) {
-            if (out->devices &
-                (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
+            if (is_speaker_active || is_speaker_safe_active) {
                 a2dp_combo = true;
             } else {
                 if (!(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
@@ -3703,12 +3725,12 @@
             }
         }
     }
-    if (out->devices & AUDIO_DEVICE_OUT_ALL_SCO) {
+    if (is_sco_out_device_type(&out->device_list)) {
         if (!adev->bt_sco_on) {
-            if (out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
+            if (is_speaker_active) {
                 //combo usecase just by pass a2dp
                 ALOGW("%s: SCO is not connected, route it to speaker", __func__);
-                out->devices = AUDIO_DEVICE_OUT_SPEAKER;
+                reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
             } else {
                 ALOGE("%s: SCO profile is not ready, return error", __func__);
                 ret = -EAGAIN;
@@ -3745,12 +3767,13 @@
     uc_info->id = out->usecase;
     uc_info->type = PCM_PLAYBACK;
     uc_info->stream.out = out;
-    uc_info->devices = out->devices;
+    list_init(&uc_info->device_list);
+    assign_devices(&uc_info->device_list, &out->device_list);
     uc_info->in_snd_device = SND_DEVICE_NONE;
     uc_info->out_snd_device = SND_DEVICE_NONE;
 
     /* This must be called before adding this usecase to the list */
-    if (audio_is_usb_out_device(out->devices & AUDIO_DEVICE_OUT_ALL_USB)) {
+    if (is_usb_out_device_type(&out->device_list)) {
        audio_extn_usb_check_and_set_svc_int(uc_info, true);
        /* USB backend is not reopened immediately.
        This is eventually done as part of select_devices */
@@ -3763,7 +3786,7 @@
                                  adev->perf_lock_opts,
                                  adev->perf_lock_opts_size);
 
-    if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+    if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
         audio_extn_keep_alive_stop(KEEP_ALIVE_OUT_HDMI);
         if (audio_extn_passthru_is_enabled() &&
             audio_extn_passthru_is_passthrough_stream(out)) {
@@ -3771,18 +3794,22 @@
         }
     }
 
-    if ((out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) &&
+    if (is_a2dp_out_device_type(&out->device_list) &&
         (!audio_extn_a2dp_source_is_ready())) {
         if (!a2dp_combo) {
             check_a2dp_restore_l(adev, out, false);
         } else {
-            audio_devices_t dev = out->devices;
-            if (dev & AUDIO_DEVICE_OUT_SPEAKER_SAFE)
-                out->devices = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+            struct listnode dev;
+            list_init(&dev);
+            assign_devices(&dev, &out->device_list);
+            if (compare_device_type(&dev, AUDIO_DEVICE_OUT_SPEAKER_SAFE))
+                reassign_device_list(&out->device_list,
+                                AUDIO_DEVICE_OUT_SPEAKER_SAFE, "");
             else
-                out->devices = AUDIO_DEVICE_OUT_SPEAKER;
+                reassign_device_list(&out->device_list,
+                                AUDIO_DEVICE_OUT_SPEAKER, "");
             select_devices(adev, out->usecase);
-            out->devices = dev;
+            assign_devices(&out->device_list, &dev);
         }
     } else {
          select_devices(adev, out->usecase);
@@ -3946,7 +3973,7 @@
             audio_extn_check_and_set_dts_hpx_state(adev);
         }
 
-        if (out->devices & AUDIO_DEVICE_OUT_BUS) {
+        if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS)) {
             /* Update cached volume from media to offload/direct stream */
             struct listnode *node = NULL;
             list_for_each(node, &adev->active_outputs_list) {
@@ -4386,7 +4413,7 @@
             stop_output_stream(out);
         }
         // if fm is active route on selected device in UI
-        audio_extn_fm_route_on_selected_device(adev, out->devices);
+        audio_extn_fm_route_on_selected_device(adev, &out->device_list);
         pthread_mutex_unlock(&adev->lock);
     }
     pthread_mutex_unlock(&out->lock);
@@ -4597,22 +4624,20 @@
 }
 
 int route_output_stream(struct stream_out *out,
-                        audio_devices_t devices,
-                        char *address)
+                        struct listnode *devices)
 {
     struct audio_device *adev = out->dev;
-    struct str_parms *addr;
     int ret = 0;
-    audio_devices_t new_devices = devices;
+    struct listnode new_devices;
     bool bypass_a2dp = false;
     bool reconfig = false;
     unsigned long service_interval = 0;
 
     ALOGD("%s: enter: usecase(%d: %s) devices %x",
-          __func__, out->usecase, use_case_table[out->usecase], devices);
-    addr = str_parms_create_str(address);
-    if (!addr)
-        goto error;
+          __func__, out->usecase, use_case_table[out->usecase], get_device_types(devices));
+
+    list_init(&new_devices);
+    assign_devices(&new_devices, devices);
 
     lock_output_stream(out);
     pthread_mutex_lock(&adev->lock);
@@ -4624,11 +4649,11 @@
      * turned off, the write gets blocked.
      * Avoid this by routing audio to speaker until standby.
      */
-    if ((out->devices == AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
-            (new_devices == AUDIO_DEVICE_NONE) &&
+    if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
+            list_empty(&new_devices) &&
             !audio_extn_passthru_is_passthrough_stream(out) &&
             (platform_get_edid_info(adev->platform) != 0) /* HDMI disconnected */) {
-        new_devices = AUDIO_DEVICE_OUT_SPEAKER;
+        reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
     }
     /*
      * When A2DP is disconnected the
@@ -4637,11 +4662,11 @@
      * (3sec). As BT is turned off, the write gets blocked.
      * Avoid this by routing audio to speaker until standby.
      */
-    if ((out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) &&
-            (new_devices == AUDIO_DEVICE_NONE) &&
+    if (is_a2dp_out_device_type(&out->device_list) &&
+            list_empty(&new_devices) &&
             !audio_extn_a2dp_source_is_ready() &&
             !adev->bt_sco_on) {
-            new_devices = AUDIO_DEVICE_OUT_SPEAKER;
+        reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
     }
     /*
      * When USB headset is disconnected the music platback paused
@@ -4650,18 +4675,18 @@
      * when USB is connected back. So routing to speker will guarantee
      * AFE reconfiguration and AFE will be opend once USB is connected again
      */
-    if ((out->devices & AUDIO_DEVICE_OUT_ALL_USB) &&
-            (new_devices == AUDIO_DEVICE_NONE) &&
-            !audio_extn_usb_connected(addr))
-        new_devices = AUDIO_DEVICE_OUT_SPEAKER;
-
+    if (is_usb_out_device_type(&out->device_list) &&
+            list_empty(&new_devices) &&
+            !audio_extn_usb_connected(NULL)) {
+        reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
+    }
     /* To avoid a2dp to sco overlapping / BT device improper state
      * check with BT lib about a2dp streaming support before routing
      */
-    if (new_devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
+    if (is_a2dp_out_device_type(&new_devices)) {
         if (!audio_extn_a2dp_source_is_ready()) {
-            if (new_devices &
-                (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
+            if (compare_device_type(&new_devices, AUDIO_DEVICE_OUT_SPEAKER) ||
+                compare_device_type(&new_devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
                 //combo usecase just by pass a2dp
                 ALOGW("%s: A2DP profile is not ready,routing to speaker only", __func__);
                 bypass_a2dp = true;
@@ -4671,7 +4696,7 @@
                  * However it is still possible a2dp routing called because
                  * of current active device disconnection (like wired headset)
                  */
-                out->devices = new_devices;
+                assign_devices(&out->device_list, &new_devices);
                 pthread_mutex_unlock(&adev->lock);
                 pthread_mutex_unlock(&out->lock);
                 goto error;
@@ -4679,17 +4704,23 @@
         }
     }
 
-
     // Workaround: If routing to an non existing usb device, fail gracefully
     // The routing request will otherwise block during 10 second
     int card;
-    if (audio_is_usb_out_device(new_devices) &&
-        (card = get_alive_usb_card(addr)) >= 0) {
-        ALOGW("out_set_parameters() ignoring rerouting to non existing USB card %d", card);
-        pthread_mutex_unlock(&adev->lock);
-        pthread_mutex_unlock(&out->lock);
-        ret = -ENOSYS;
-        goto error;
+    if (is_usb_out_device_type(&new_devices)) {
+        struct str_parms *parms =
+            str_parms_create_str(get_usb_device_address(&new_devices));
+        if (!parms)
+            goto error;
+        if ((card = get_alive_usb_card(parms)) >= 0) {
+            ALOGW("%s: ignoring rerouting to non existing USB card %d", __func__, card);
+            pthread_mutex_unlock(&adev->lock);
+            pthread_mutex_unlock(&out->lock);
+            str_parms_destroy(parms);
+            ret = -ENOSYS;
+            goto error;
+        }
+        str_parms_destroy(parms);
     }
 
     /*
@@ -4710,15 +4741,15 @@
      *       Because select_devices() must be called to switch back the music
      *       playback to headset.
      */
-    if (new_devices != AUDIO_DEVICE_NONE) {
-        bool same_dev = out->devices == new_devices;
-        out->devices = new_devices;
+    if (!list_empty(&new_devices)) {
+        bool same_dev = compare_devices(&out->device_list, &new_devices);
+        assign_devices(&out->device_list, &new_devices);
 
         if (output_drives_call(adev, out)) {
             if (!voice_is_call_state_active(adev)) {
                 if (adev->mode == AUDIO_MODE_IN_CALL) {
                     adev->current_call_output = out;
-                    if (audio_is_usb_out_device(out->devices & AUDIO_DEVICE_OUT_ALL_USB)) {
+                    if (is_usb_out_device_type(&out->device_list)) {
                         service_interval =
                             audio_extn_usb_find_service_interval(true, true /*playback*/);
                         audio_extn_usb_set_service_interval(true /*playback*/,
@@ -4747,12 +4778,12 @@
             if (!bypass_a2dp) {
                 select_devices(adev, out->usecase);
             } else {
-                if (new_devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE)
-                    out->devices = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+                if (compare_device_type(&new_devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE))
+                    reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE, "");
                 else
-                    out->devices = AUDIO_DEVICE_OUT_SPEAKER;
+                    reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
                 select_devices(adev, out->usecase);
-                out->devices = new_devices;
+                assign_devices(&out->device_list, &new_devices);
             }
 
             if (!same_dev) {
@@ -4763,7 +4794,7 @@
             }
             if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
                  out->a2dp_compress_mute &&
-                 (!(out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) || audio_extn_a2dp_source_is_ready())) {
+                 (!is_a2dp_out_device_type(&out->device_list) || audio_extn_a2dp_source_is_ready())) {
                 pthread_mutex_lock(&out->compr_mute_lock);
                 out->a2dp_compress_mute = false;
                 out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
@@ -4781,8 +4812,6 @@
     audio_extn_extspk_update(adev->extspk);
 
 error:
-    if (addr)
-        str_parms_destroy(addr);
     ALOGV("%s: exit: code(%d)", __func__, ret);
     return ret;
 }
@@ -4844,7 +4873,8 @@
         lock_output_stream(out);
         audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
                                                           &adev->streams_output_cfg_list,
-                                                          out->devices, out->flags, out->hal_op_format,
+                                                          &out->device_list, out->flags,
+                                                          out->hal_op_format,
                                                           out->sample_rate, out->bit_width,
                                                           out->channel_mask, out->profile,
                                                           &out->app_type_cfg);
@@ -5173,7 +5203,7 @@
            (out->config.rate);
     }
 
-    if (AUDIO_DEVICE_OUT_ALL_A2DP & out->devices)
+    if (is_a2dp_out_device_type(&out->device_list))
         latency += audio_extn_a2dp_get_encoder_latency();
 
     ALOGV("%s: Latency %d", __func__, latency);
@@ -5347,7 +5377,7 @@
             volume[1] = (long)(AmpToDb(right));
             mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
             return 0;
-        } else if ((out->devices & AUDIO_DEVICE_OUT_BUS) &&
+        } else if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS) &&
                 (out->car_audio_stream == CAR_AUDIO_STREAM_MEDIA)) {
             ALOGD("%s: Overriding offload set volume for media bus stream", __func__);
             struct listnode *node = NULL;
@@ -5541,6 +5571,7 @@
     const size_t frame_size = audio_stream_out_frame_size(stream);
     const size_t frames = (frame_size != 0) ? bytes / frame_size : bytes;
     struct audio_usecase *usecase = NULL;
+    uint32_t compr_passthr = 0;
 
     ATRACE_BEGIN("out_write");
     lock_output_stream(out);
@@ -5571,7 +5602,7 @@
         goto exit;
     }
 
-    if ((out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
+    if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
          !out->is_iec61937_info_available) {
 
         if (!audio_extn_passthru_is_passthrough_stream(out)) {
@@ -5608,8 +5639,15 @@
                 }
             }
 
+#ifdef AUDIO_GKI_ENABLED
+            /* out->compr_config.codec->reserved[0] is for compr_passthr */
+            compr_passthr = out->compr_config.codec->reserved[0];
+#else
+            compr_passthr = out->compr_config.codec->compr_passthr;
+#endif
+
             if ((channels < (int)audio_channel_count_from_out_mask(out->channel_mask)) &&
-                (out->compr_config.codec->compr_passthr == PASSTHROUGH) &&
+                (compr_passthr == PASSTHROUGH) &&
                 (out->is_iec61937_info_available == true)) {
                     ALOGE("%s: ERROR: Unsupported channel config in passthrough mode", __func__);
                     ret = -EINVAL;
@@ -5618,10 +5656,10 @@
         }
     }
 
-    if ((out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) &&
+    if (is_a2dp_out_device_type(&out->device_list) &&
         (audio_extn_a2dp_source_is_suspended())) {
-        if (!(out->devices &
-            (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_SPEAKER_SAFE))) {
+        if (!(compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER) ||
+              compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE))) {
             if (!(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
                 ret = -EIO;
                 goto exit;
@@ -5659,7 +5697,9 @@
             audio_extn_send_dual_mono_mixing_coefficients(out);
     }
 
-    if (adev->is_channel_status_set == false && (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)){
+    if (adev->is_channel_status_set == false &&
+            compare_device_type(&out->device_list,
+                                AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
         audio_utils_set_hdmi_channel_status(out, (void *)buffer, bytes);
         adev->is_channel_status_set = true;
     }
@@ -6016,7 +6056,7 @@
                  &out->sample_rate);
         // Adjustment accounts for A2dp encoder latency with offload usecases
         // Note: Encoder latency is returned in ms.
-        if (AUDIO_DEVICE_OUT_ALL_A2DP & out->devices) {
+        if (is_a2dp_out_device_type(&out->device_list)) {
             unsigned long offset =
                         (audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000);
             dsp_frames = (dsp_frames > offset) ? (dsp_frames - offset) : 0;
@@ -6055,7 +6095,7 @@
 
                 // Adjustment accounts for A2dp encoder latency with non offload usecases
                 // Note: Encoder latency is returned in ms, while platform_render_latency in us.
-                if (AUDIO_DEVICE_OUT_ALL_A2DP & out->devices) {
+                if (is_a2dp_out_device_type(&out->device_list)) {
                     frames_temp = audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000;
                     if (signed_frames >= frames_temp)
                         signed_frames -= frames_temp;
@@ -6583,8 +6623,7 @@
 }
 
 int route_input_stream(struct stream_in *in,
-                       audio_devices_t devices,
-                       char *address,
+                       struct listnode *devices,
                        audio_source_t source)
 {
     struct audio_device *adev = in->dev;
@@ -6610,22 +6649,20 @@
         }
     }
 
-    if ((in->device != devices) && (devices != AUDIO_DEVICE_NONE) &&
-          audio_is_input_device(devices)) {
+    if (!compare_devices(&in->device_list, devices) && !list_empty(devices) &&
+          is_audio_in_device_type(devices)) {
         // Workaround: If routing to an non existing usb device, fail gracefully
         // The routing request will otherwise block during 10 second
         int card;
-        struct str_parms *addr = str_parms_create_str(address);
-
-        if (!addr)
-            return ret;
-        if (audio_is_usb_in_device(devices) &&
-            (card = get_alive_usb_card(addr)) >= 0) {
+        struct str_parms *usb_addr =
+                str_parms_create_str(get_usb_device_address(devices));
+        if (is_usb_in_device_type(devices) && usb_addr &&
+             (card = get_alive_usb_card(usb_addr)) >= 0) {
             ALOGW("%s: ignoring rerouting to non existing USB card %d", __func__, card);
             ret = -ENOSYS;
         } else {
-            in->device = devices;
             /* If recording is in progress, change the tx device to new device */
+            assign_devices(&in->device_list, devices);
             if (!in->standby && !in->is_st_session) {
                 ALOGV("update input routing change");
                 // inform adm before actual routing to prevent glitches.
@@ -6638,7 +6675,8 @@
                 }
             }
         }
-        str_parms_destroy(addr);
+        if (usb_addr)
+            str_parms_destroy(usb_addr);
     }
     pthread_mutex_unlock(&adev->lock);
     pthread_mutex_unlock(&in->lock);
@@ -6669,7 +6707,7 @@
         ALOGV("updating stream profile with value '%s'", in->profile);
         audio_extn_utils_update_stream_input_app_type_cfg(adev->platform,
                                                           &adev->streams_input_cfg_list,
-                                                          in->device, in->flags, in->format,
+                                                          &in->device_list, in->flags, in->format,
                                                           in->sample_rate, in->bit_width,
                                                           in->profile, &in->app_type_cfg);
     }
@@ -7345,22 +7383,24 @@
     int error = 0;
     struct stream_in *in = (struct stream_in *)stream;
     struct audio_device *adev = in->dev;
-    audio_devices_t device = AUDIO_DEVICE_NONE;
+    struct listnode devices;
+
+    list_init(&devices);
 
     if (sink_metadata->track_count != 0)
-        device = sink_metadata->tracks->dest_device;
+        reassign_device_list(&devices, sink_metadata->tracks->dest_device, "");
 
     lock_input_stream(in);
     pthread_mutex_lock(&adev->lock);
-    ALOGV("%s: in->usecase: %d, device: %x", __func__, in->usecase, device);
+    ALOGV("%s: in->usecase: %d, device: %x", __func__, in->usecase, get_device_types(&devices));
 
     if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY
-            && device != AUDIO_DEVICE_NONE
+            && !list_empty(&devices)
             && adev->voice_tx_output != NULL) {
         /* Use the rx device from afe-proxy record to route voice call because
            there is no routing if tx device is on primary hal and rx device
            is on other hal during voice call. */
-        adev->voice_tx_output->devices = device;
+        assign_devices(&adev->voice_tx_output->device_list, &devices);
 
         if (!voice_is_call_state_active(adev)) {
             if (adev->mode == AUDIO_MODE_IN_CALL) {
@@ -7443,7 +7483,8 @@
         devices = AUDIO_DEVICE_OUT_SPEAKER;
 
     out->flags = flags;
-    out->devices = devices;
+    list_init(&out->device_list);
+    update_device_list(&out->device_list, devices, address, true /* add devices */);
     out->dev = adev;
     out->hal_op_format = out->hal_ip_format = format = out->format = config->format;
     out->sample_rate = config->sample_rate;
@@ -7551,7 +7592,7 @@
     }
 
     /* validate bus device address */
-    if (out->devices & AUDIO_DEVICE_OUT_BUS) {
+    if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS)) {
         /* extract car audio stream index */
         out->car_audio_stream =
             audio_extn_auto_hal_get_car_audio_stream_from_address(address);
@@ -7687,11 +7728,16 @@
 
         if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
             ALOGD("%s: Setting latency mode to true", __func__);
+#ifdef AUDIO_GKI_ENABLED
+            /* out->compr_config.codec->reserved[1] is for flags */
+            out->compr_config.codec->reserved[1] |= audio_extn_utils_get_perf_mode_flag();
+#else
             out->compr_config.codec->flags |= audio_extn_utils_get_perf_mode_flag();
+#endif
         }
 
         if (out->usecase == USECASE_INVALID) {
-            if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL &&
+            if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
                     config->format == 0 && config->sample_rate == 0 &&
                     config->channel_mask == 0) {
                 ALOGI("%s dummy open to query sink capability",__func__);
@@ -7739,8 +7785,14 @@
             out->bit_width = AUDIO_OUTPUT_BIT_WIDTH;
 
         if (out->flags & AUDIO_OUTPUT_FLAG_TIMESTAMP)
+#ifdef AUDIO_GKI_ENABLED
+            /* out->compr_config.codec->reserved[1] is for flags */
+            out->compr_config.codec->reserved[1] |= COMPRESSED_TIMESTAMP_FLAG;
+        ALOGVV("%s : out->compr_config.codec->flags -> (%#x) ", __func__, out->compr_config.codec->reserved[1]);
+#else
             out->compr_config.codec->flags |= COMPRESSED_TIMESTAMP_FLAG;
         ALOGVV("%s : out->compr_config.codec->flags -> (%#x) ", __func__, out->compr_config.codec->flags);
+#endif
 
         /*TODO: Do we need to change it for passthrough */
         out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
@@ -7879,7 +7931,12 @@
         }
         if (config->format == AUDIO_FORMAT_DSD) {
             out->flags |= AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH;
+#ifdef AUDIO_GKI_ENABLED
+            /* out->compr_config.codec->reserved[0] is for compr_passthr */
+            out->compr_config.codec->reserved[0] = PASSTHROUGH_DSD;
+#else
             out->compr_config.codec->compr_passthr = PASSTHROUGH_DSD;
+#endif
         }
 
         create_offload_callback_thread(out);
@@ -7933,7 +7990,8 @@
                 __func__, ret);
             goto error_open;
         }
-    } else if (out->devices == AUDIO_DEVICE_OUT_TELEPHONY_TX) {
+    } else if (is_single_device_type_equal(&out->device_list,
+                                           AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
         switch (config->sample_rate) {
             case 0:
                 out->sample_rate = AFE_PROXY_SAMPLING_RATE;
@@ -8063,7 +8121,7 @@
                 adev->haptics_config.channels = 1;
             } else
                 adev->haptics_config.channels = audio_channel_count_from_out_mask(out->channel_mask & AUDIO_CHANNEL_HAPTIC_ALL);
-        } else if (out->devices & AUDIO_DEVICE_OUT_BUS) {
+        } else if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS)) {
             ret = audio_extn_auto_hal_open_output_stream(out);
             if (ret) {
                 ALOGE("%s: Failed to open output stream for bus device", __func__);
@@ -8105,7 +8163,8 @@
         out->bit_width = 16;
     audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
                                                 &adev->streams_output_cfg_list,
-                                                devices, out->flags, out->hal_op_format, out->sample_rate,
+                                                &out->device_list, out->flags,
+                                                out->hal_op_format, out->sample_rate,
                                                 out->bit_width, out->channel_mask, out->profile,
                                                 &out->app_type_cfg);
     if ((out->usecase == (audio_usecase_t)(GET_USECASE_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary))) ||
@@ -8392,10 +8451,10 @@
             list_for_each(node, &adev->usecase_list) {
                 usecase = node_to_item(node, struct audio_usecase, list);
                 if (usecase->stream.in && (usecase->type == PCM_CAPTURE) &&
-                    ((usecase->stream.in->device & ~AUDIO_DEVICE_BIT_IN) &
-                        AUDIO_DEVICE_IN_ALL_SCO)) {
+                    is_sco_in_device_type(&usecase->stream.in->device_list)) {
                     ALOGD("a2dp resumed, switch bt sco mic to handset mic");
-                    usecase->stream.in->device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+                    reassign_device_list(&usecase->stream.in->device_list,
+                                         AUDIO_DEVICE_IN_BUILTIN_MIC, "");
                     select_devices(adev, usecase->id);
                 }
             }
@@ -8542,7 +8601,7 @@
         list_for_each(node, &adev->usecase_list) {
             usecase = node_to_item(node, struct audio_usecase, list);
             if (usecase->stream.out && (usecase->type == PCM_PLAYBACK) &&
-                (usecase->devices & AUDIO_DEVICE_OUT_ALL_A2DP)){
+                is_a2dp_out_device_type(&usecase->device_list)) {
                 ALOGD("reconfigure a2dp... forcing device switch");
                 pthread_mutex_unlock(&adev->lock);
                 lock_output_stream(usecase->stream.out);
@@ -8563,7 +8622,8 @@
                 pthread_mutex_unlock(&adev->lock);
                 lock_output_stream(usecase->stream.out);
                 pthread_mutex_lock(&adev->lock);
-                usecase->stream.out->devices = AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+                reassign_device_list(&usecase->stream.out->device_list,
+                                     AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, "");
                 check_a2dp_restore_l(adev, usecase->stream.out, true);
                 pthread_mutex_unlock(&usecase->stream.out->lock);
                 break;
@@ -8898,7 +8958,7 @@
                                   struct audio_config *config,
                                   struct audio_stream_in **stream_in,
                                   audio_input_flags_t flags,
-                                  const char *address __unused,
+                                  const char *address,
                                   audio_source_t source)
 {
     struct audio_device *adev = (struct audio_device *)dev;
@@ -8984,7 +9044,8 @@
     in->stream.set_microphone_field_dimension = in_set_microphone_field_dimension;
     in->stream.update_sink_metadata = in_update_sink_metadata;
 
-    in->device = devices;
+    list_init(&in->device_list);
+    update_device_list(&in->device_list, devices, address, true);
     in->source = source;
     in->dev = adev;
     in->standby = 1;
@@ -9144,8 +9205,10 @@
         default:
             in->bit_width = 16;
         }
-    } else if ((in->device == AUDIO_DEVICE_IN_TELEPHONY_RX) ||
-             (in->device == AUDIO_DEVICE_IN_PROXY)) {
+    } else if (is_single_device_type_equal(&in->device_list,
+                                           AUDIO_DEVICE_IN_TELEPHONY_RX) ||
+               is_single_device_type_equal(&in->device_list,
+                                           AUDIO_DEVICE_IN_PROXY)) {
         if (config->sample_rate == 0)
             config->sample_rate = AFE_PROXY_SAMPLING_RATE;
         if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
@@ -9270,7 +9333,7 @@
 
     audio_extn_utils_update_stream_input_app_type_cfg(adev->platform,
                                                 &adev->streams_input_cfg_list,
-                                                devices, flags, in->format,
+                                                &in->device_list, flags, in->format,
                                                 in->sample_rate, in->bit_width,
                                                 in->profile, &in->app_type_cfg);
     register_format(in->format, in->supported_formats);
@@ -9337,6 +9400,10 @@
 
     ALOGD("%s: enter:stream_handle(%p)",__func__, in);
 
+    if (in == NULL) {
+        ALOGE("%s: audio_stream_in ptr is NULL", __func__);
+        return;
+    }
     io_streams_map_remove(adev, in->capture_handle);
 
     /* must deregister from sndmonitor first to prevent races
@@ -9349,15 +9416,13 @@
      */
     if (adev_get_active_input(adev) == NULL &&
         !audio_extn_hfp_is_active(adev) &&
-        !audio_extn_sound_trigger_check_ec_ref_enable())
-        platform_set_echo_reference(adev, false, AUDIO_DEVICE_NONE);
-    else
+        !audio_extn_sound_trigger_check_ec_ref_enable()) {
+        struct listnode out_devices;
+        list_init(&out_devices);
+        platform_set_echo_reference(adev, false, &out_devices);
+    } else
         audio_extn_sound_trigger_update_ec_ref_status(false);
 
-    if (in == NULL) {
-        ALOGE("%s: audio_stream_in ptr is NULL", __func__);
-        return;
-    }
     error_log_destroy(in->error_log);
     in->error_log = NULL;
 
@@ -9496,14 +9561,14 @@
             uc_info.type = usecase_type;
             if (dir) {
                 memset(&in, 0, sizeof(in));
-                in.device = audio_device;
+                update_device_list(&in.device_list, audio_device, "", true);
                 in.source = AUDIO_SOURCE_VOICE_COMMUNICATION;
                 uc_info.stream.in = &in;
             }
             memset(&out, 0, sizeof(out));
-            out.devices = audio_device; /* only field needed in select_devices */
+            update_device_list(&out.device_list, audio_device, "", true);
             uc_info.stream.out = &out;
-            uc_info.devices = audio_device;
+            update_device_list(&uc_info.device_list, audio_device, "", true);
             uc_info.in_snd_device = SND_DEVICE_NONE;
             uc_info.out_snd_device = SND_DEVICE_NONE;
             list_add_tail(&adev->usecase_list, &uc_info.list);
@@ -9595,6 +9660,7 @@
     audio_source_t input_source = AUDIO_SOURCE_DEFAULT;
     struct audio_stream_info *s_info = NULL;
     struct audio_stream *stream = NULL;
+    struct listnode devices;
     audio_devices_t device_type = AUDIO_DEVICE_NONE;
     bool new_patch = false;
     char addr[AUDIO_DEVICE_MAX_ADDRESS_LEN];
@@ -9623,17 +9689,19 @@
 
     ALOGV("%s: source role %d, source type %d", __func__,
            sources[0].type, sources[0].role);
+    list_init(&devices);
 
     // Populate source/sink information and fetch stream info
     switch (sources[0].type) {
         case AUDIO_PORT_TYPE_DEVICE: // Patch for audio capture or loopback
             device_type = sources[0].ext.device.type;
             strlcpy(&addr[0], &sources[0].ext.device.address[0], AUDIO_DEVICE_MAX_ADDRESS_LEN);
+            update_device_list(&devices, device_type, &addr[0], true);
             if (sinks[0].type == AUDIO_PORT_TYPE_MIX) {
                 patch_type = PATCH_CAPTURE;
                 io_handle = sinks[0].ext.mix.handle;
                 input_source = sinks[0].ext.mix.usecase.source;
-                ALOGV("%s: Capture patch from device %x to mix %d",
+                ALOGD("%s: Capture patch from device %x to mix %d",
                        __func__, device_type, io_handle);
             } else {
                 // Device to device patch is not implemented.
@@ -9645,103 +9713,91 @@
         case AUDIO_PORT_TYPE_MIX: // Patch for audio playback
             io_handle = sources[0].ext.mix.handle;
             for (int i = 0; i < num_sinks; i++) {
-                if (sinks[i].type == AUDIO_PORT_TYPE_MIX) {
-                    ALOGE("%s: mix to mix patches are not supported", __func__);
-                    ret = -EINVAL;
-                    goto done;
-                }
-                device_type |= sinks[i].ext.device.type;
+                device_type = sinks[i].ext.device.type;
                 strlcpy(&addr[0], &sinks[i].ext.device.address[0], AUDIO_DEVICE_MAX_ADDRESS_LEN);
+                update_device_list(&devices, device_type, &addr[0], true);
             }
             patch_type = PATCH_PLAYBACK;
-            ALOGV("%s: Playback patch from mix handle %d to device %x",
-                   __func__, io_handle, device_type);
+            ALOGD("%s: Playback patch from mix handle %d to device %x",
+                   __func__, io_handle, get_device_types(&devices));
             break;
         case AUDIO_PORT_TYPE_SESSION:
         case AUDIO_PORT_TYPE_NONE:
-            break;
+            ALOGE("%s: Unsupported source type %d", __func__, sources[0].type);
+            ret = -EINVAL;
+            goto done;
     }
 
     pthread_mutex_lock(&adev->lock);
-    s_info = hashmapGet(adev->io_streams_map, (void *) (intptr_t) io_handle);
-    pthread_mutex_unlock(&adev->lock);
-    if (s_info == NULL) {
-        ALOGE("%s: Failed to obtain stream info", __func__);
-        ret = -EINVAL;
-        goto done;
-    }
-    ALOGV("%s: Fetched stream info with io_handle %d", __func__, io_handle);
 
-    pthread_mutex_lock(&s_info->lock);
     // Generate patch info and update patch
     if (*handle == AUDIO_PATCH_HANDLE_NONE) {
-        if (s_info->patch_handle != AUDIO_PATCH_HANDLE_NONE) {
-            // Use patch handle cached in s_info to update patch
-            *handle = s_info->patch_handle;
-            p_info = fetch_patch_info(adev, *handle);
-            if (p_info == NULL) {
-                ALOGE("%s: Unable to fetch patch for stream patch handle %d",
-                      __func__, *handle);
-                pthread_mutex_unlock(&s_info->lock);
-                ret = -EINVAL;
-                goto done;
-            }
-        } else {
-            *handle = generate_patch_handle();
-            p_info = (struct audio_patch_info *) calloc(1, sizeof(struct audio_patch_info));
-            if (p_info == NULL) {
-                ALOGE("%s: Failed to allocate memory", __func__);
-                pthread_mutex_unlock(&s_info->lock);
-                ret = -ENOMEM;
-                goto done;
-            }
-            new_patch = true;
-            pthread_mutex_init(&p_info->lock, (const pthread_mutexattr_t *) NULL);
-            s_info->patch_handle = *handle;
+        *handle = generate_patch_handle();
+        p_info = (struct audio_patch_info *)
+                      calloc(1, sizeof(struct audio_patch_info));
+        if (p_info == NULL) {
+            ALOGE("%s: Failed to allocate memory", __func__);
+            pthread_mutex_unlock(&adev->lock);
+            ret = -ENOMEM;
+            goto done;
         }
+        new_patch = true;
     } else {
-        p_info = fetch_patch_info(adev, *handle);
+        p_info = fetch_patch_info_l(adev, *handle);
         if (p_info == NULL) {
             ALOGE("%s: Unable to fetch patch for received patch handle %d",
                   __func__, *handle);
-            pthread_mutex_unlock(&s_info->lock);
+            pthread_mutex_unlock(&adev->lock);
             ret = -EINVAL;
             goto done;
         }
-        s_info->patch_handle = *handle;
     }
-    pthread_mutex_lock(&p_info->lock);
     update_patch(num_sources, sources, num_sinks, sinks,
-                 *handle, p_info, patch_type, new_patch);
-    stream = s_info->stream;
+             *handle, p_info, patch_type, new_patch);
+
+    // Fetch stream info of associated mix for playback or capture patches
+    if (p_info->patch_type == PATCH_PLAYBACK ||
+            p_info->patch_type == PATCH_CAPTURE) {
+        s_info = hashmapGet(adev->io_streams_map, (void *) (intptr_t) io_handle);
+        if (s_info == NULL) {
+            ALOGE("%s: Failed to obtain stream info", __func__);
+            if (new_patch)
+                free(p_info);
+            pthread_mutex_unlock(&adev->lock);
+            ret = -EINVAL;
+            goto done;
+        }
+        ALOGV("%s: Fetched stream info with io_handle %d", __func__, io_handle);
+        s_info->patch_handle = *handle;
+        stream = s_info->stream;
+    }
+    pthread_mutex_unlock(&adev->lock);
 
     // Update routing for stream
     if (stream != NULL) {
         if (p_info->patch_type == PATCH_PLAYBACK)
-            ret = route_output_stream((struct stream_out *) stream, device_type, &addr[0]);
+            ret = route_output_stream((struct stream_out *) stream, &devices);
         else if (p_info->patch_type == PATCH_CAPTURE)
-            ret = route_input_stream((struct stream_in *) stream,
-                                     device_type, &addr[0], input_source);
-    }
-
-    if (ret < 0) {
-        s_info->patch_handle = AUDIO_PATCH_HANDLE_NONE;
-        ALOGE("%s: Stream routing failed for io_handle %d", __func__, io_handle);
-        pthread_mutex_unlock(&p_info->lock);
-        pthread_mutex_unlock(&s_info->lock);
-        goto done;
+            ret = route_input_stream((struct stream_in *) stream, &devices, input_source);
+        if (ret < 0) {
+            pthread_mutex_lock(&adev->lock);
+            s_info->patch_handle = AUDIO_PATCH_HANDLE_NONE;
+            if (new_patch)
+                free(p_info);
+            pthread_mutex_unlock(&adev->lock);
+            ALOGE("%s: Stream routing failed for io_handle %d", __func__, io_handle);
+            goto done;
+        }
     }
 
     // Add new patch to patch map
     if (!ret && new_patch) {
         pthread_mutex_lock(&adev->lock);
         hashmapPut(adev->patch_map, (void *) (intptr_t) *handle, (void *) p_info);
-        pthread_mutex_unlock(&adev->lock);
         ALOGD("%s: Added a new patch with handle %d", __func__, *handle);
+        pthread_mutex_unlock(&adev->lock);
     }
 
-    pthread_mutex_unlock(&p_info->lock);
-    pthread_mutex_unlock(&s_info->lock);
 done:
     audio_extn_hw_loopback_create_audio_patch(dev,
                                         num_sources,
@@ -9763,8 +9819,8 @@
 {
     struct audio_device *adev = (struct audio_device *) dev;
     int ret = 0;
-    char *addr = "";
     audio_source_t input_source = AUDIO_SOURCE_DEFAULT;
+    struct audio_stream *stream = NULL;
 
     if (handle == AUDIO_PATCH_HANDLE_NONE) {
         ALOGE("%s: Invalid patch handle %d", __func__, handle);
@@ -9773,64 +9829,65 @@
     }
 
     ALOGD("%s: Remove patch with handle %d", __func__, handle);
-    struct audio_patch_info *p_info = fetch_patch_info(adev, handle);
+    pthread_mutex_lock(&adev->lock);
+    struct audio_patch_info *p_info = fetch_patch_info_l(adev, handle);
     if (p_info == NULL) {
         ALOGE("%s: Patch info not found with handle %d", __func__, handle);
+        pthread_mutex_unlock(&adev->lock);
         ret = -EINVAL;
         goto done;
     }
-    pthread_mutex_lock(&p_info->lock);
     struct audio_patch *patch = p_info->patch;
     if (patch == NULL) {
         ALOGE("%s: Patch not found for handle %d", __func__, handle);
+        pthread_mutex_unlock(&adev->lock);
         ret = -EINVAL;
-        pthread_mutex_unlock(&p_info->lock);
         goto done;
     }
-    pthread_mutex_unlock(&p_info->lock);
     audio_io_handle_t io_handle = AUDIO_IO_HANDLE_NONE;
     switch (patch->sources[0].type) {
         case AUDIO_PORT_TYPE_MIX:
             io_handle = patch->sources[0].ext.mix.handle;
             break;
         case AUDIO_PORT_TYPE_DEVICE:
-            io_handle = patch->sinks[0].ext.mix.handle;
+            if (p_info->patch_type == PATCH_CAPTURE)
+                io_handle = patch->sinks[0].ext.mix.handle;
             break;
         case AUDIO_PORT_TYPE_SESSION:
         case AUDIO_PORT_TYPE_NONE:
-            break;
+            pthread_mutex_unlock(&adev->lock);
+            ret = -EINVAL;
+            goto done;
     }
 
     // Remove patch and reset patch handle in stream info
-    pthread_mutex_lock(&adev->lock);
-    struct audio_stream_info *s_info =
-        hashmapGet(adev->io_streams_map, (void *) (intptr_t) io_handle);
-    pthread_mutex_unlock(&adev->lock);
-    if (s_info == NULL) {
-        ALOGE("%s: stream for io_handle %d is not available", __func__, io_handle);
-        goto done;
+    patch_map_remove_l(adev, handle);
+    if (p_info->patch_type == PATCH_PLAYBACK ||
+        p_info->patch_type == PATCH_CAPTURE) {
+        struct audio_stream_info *s_info =
+            hashmapGet(adev->io_streams_map, (void *) (intptr_t) io_handle);
+        if (s_info == NULL) {
+            ALOGE("%s: stream for io_handle %d is not available", __func__, io_handle);
+            pthread_mutex_unlock(&adev->lock);
+            goto done;
+        }
+        s_info->patch_handle = AUDIO_PATCH_HANDLE_NONE;
+        stream = s_info->stream;
     }
-    pthread_mutex_lock(&s_info->lock);
-    s_info->patch_handle = AUDIO_PATCH_HANDLE_NONE;
-    struct audio_stream *stream = s_info->stream;
+    pthread_mutex_unlock(&adev->lock);
 
-    pthread_mutex_lock(&p_info->lock);
     if (stream != NULL) {
+        struct listnode devices;
+        list_init(&devices);
         if (p_info->patch_type == PATCH_PLAYBACK)
-            ret = route_output_stream((struct stream_out *)stream, AUDIO_DEVICE_NONE, addr);
+            ret = route_output_stream((struct stream_out *) stream, &devices);
         else if (p_info->patch_type == PATCH_CAPTURE)
-            ret = route_input_stream((struct stream_in *)stream,
-                                      AUDIO_DEVICE_NONE, addr, input_source);
+            ret = route_input_stream((struct stream_in *) stream, &devices, input_source);
     }
 
     if (ret < 0)
         ALOGW("%s: Stream routing failed for io_handle %d", __func__, io_handle);
 
-    pthread_mutex_unlock(&p_info->lock);
-    pthread_mutex_unlock(&s_info->lock);
-
-    // Remove patch entry from map
-    patch_map_remove(adev, handle);
 done:
     audio_extn_hw_loopback_release_audio_patch(dev, handle);
     audio_extn_auto_hal_release_audio_patch(dev, handle);
@@ -9982,7 +10039,7 @@
     struct audio_usecase *uc_info;
     float left_p;
     float right_p;
-    audio_devices_t devices;
+    struct listnode devices;
 
     uc_info = get_usecase_from_list(adev, out->usecase);
     if (uc_info == NULL) {
@@ -9996,7 +10053,7 @@
 
     if (restore) {
         // restore A2DP device for active usecases and unmute if required
-        if (out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
+        if (is_a2dp_out_device_type(&out->device_list)) {
             ALOGD("%s: restoring A2dp and unmuting stream", __func__);
             if (uc_info->out_snd_device != SND_DEVICE_OUT_BT_A2DP)
                 select_devices(adev, uc_info->id);
@@ -10014,8 +10071,8 @@
             pthread_mutex_lock(&out->compr_mute_lock);
             if (!out->a2dp_compress_mute && !out->standby) {
                 ALOGD("%s: selecting speaker and muting stream", __func__);
-                devices = out->devices;
-                out->devices = AUDIO_DEVICE_OUT_SPEAKER;
+                assign_devices(&devices, &out->device_list);
+                reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
                 left_p = out->volume_l;
                 right_p = out->volume_r;
                 if (out->offload_state == OFFLOAD_STATE_PLAYING)
@@ -10025,7 +10082,7 @@
                 select_devices(adev, out->usecase);
                 if (out->offload_state == OFFLOAD_STATE_PLAYING)
                     compress_resume(out->compr);
-                out->devices = devices;
+                assign_devices(&out->device_list, &devices);
                 out->volume_l = left_p;
                 out->volume_r = right_p;
             }
@@ -10403,8 +10460,7 @@
 adev_open_err:
     free_map(adev->patch_map);
     free_map(adev->io_streams_map);
-    if (adev->snd_dev_ref_cnt)
-        free(adev->snd_dev_ref_cnt);
+    free(adev->snd_dev_ref_cnt);
     pthread_mutex_destroy(&adev->lock);
     free(adev);
     adev = NULL;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 5604977..a4cb2e8 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -51,6 +51,7 @@
 #include "audio_defs.h"
 #include "voice.h"
 #include "audio_hw_extn_api.h"
+#include "device_utils.h"
 
 #if LINUX_ENABLED
 #if defined(__LP64__)
@@ -334,7 +335,7 @@
     unsigned int sample_rate;
     audio_channel_mask_t channel_mask;
     audio_format_t format;
-    audio_devices_t devices;
+    struct listnode device_list;
     unsigned int bit_width;
 };
 
@@ -368,7 +369,7 @@
     unsigned int sample_rate;
     audio_channel_mask_t channel_mask;
     audio_format_t format;
-    audio_devices_t devices;
+    struct listnode device_list;
     audio_output_flags_t flags;
     char profile[MAX_STREAM_PROFILE_STR_LEN];
     audio_usecase_t usecase;
@@ -465,7 +466,7 @@
     int standby;
     int source;
     int pcm_device_id;
-    audio_devices_t device;
+    struct listnode device_list;
     audio_channel_mask_t channel_mask;
     audio_usecase_t usecase;
     bool enable_aec;
@@ -531,13 +532,11 @@
 struct audio_patch_info {
     struct audio_patch *patch;
     patch_type_t patch_type;
-    pthread_mutex_t lock;
 };
 
 struct audio_stream_info {
     struct audio_stream *stream;
     audio_patch_handle_t patch_handle;
-    pthread_mutex_t lock;
 };
 
 union stream_ptr {
@@ -550,7 +549,7 @@
     struct listnode list;
     audio_usecase_t id;
     usecase_type_t  type;
-    audio_devices_t devices;
+    struct listnode device_list;
     snd_device_t out_snd_device;
     snd_device_t in_snd_device;
     struct stream_app_type_cfg out_app_type_cfg;
@@ -798,12 +797,10 @@
 }
 
 int route_output_stream(struct stream_out *stream,
-                               audio_devices_t devices,
-                               char *address);
+                        struct listnode *devices);
 int route_input_stream(struct stream_in *stream,
-                              audio_devices_t devices,
-                              char *address,
-                              audio_source_t source);
+                       struct listnode *devices,
+                       audio_source_t source);
 
 /*
  * NOTE: when multiple mutexes have to be acquired, always take the
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 4a70358..3222516 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -210,7 +210,6 @@
     "audio/x-ape" /*ape */,
 };
 
-
 enum {
     VOICE_FEATURE_SET_DEFAULT,
     VOICE_FEATURE_SET_VOLUME_BOOST
@@ -1862,7 +1861,7 @@
 }
 
 void platform_set_echo_reference(struct audio_device *adev, bool enable,
-                                 audio_devices_t out_device)
+                                 struct listnode *out_devices)
 {
     struct platform_data *my_data = (struct platform_data *)adev->platform;
     char ec_ref_mixer_path[MIXER_PATH_MAX_LENGTH] = "echo-reference";
@@ -1898,16 +1897,16 @@
         else if (adev->snd_dev_ref_cnt[SND_DEVICE_OUT_DISPLAY_PORT1] > 0)
             strlcat(ec_ref_mixer_path, " display-port1",
                     MIXER_PATH_MAX_LENGTH);
-        else if (out_device & AUDIO_DEVICE_OUT_EARPIECE)
+        else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_EARPIECE))
             strlcat(ec_ref_mixer_path, " handset",
                     MIXER_PATH_MAX_LENGTH);
-        else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE)
+        else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_WIRED_HEADPHONE))
             strlcat(ec_ref_mixer_path, " headphones",
                     MIXER_PATH_MAX_LENGTH);
-        else if (out_device & AUDIO_DEVICE_OUT_USB_HEADSET)
+        else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_USB_HEADSET))
             strlcat(ec_ref_mixer_path, " usb-headphones",
                     MIXER_PATH_MAX_LENGTH);
-        else if (out_device & AUDIO_DEVICE_OUT_BUS)
+        else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_BUS))
             strlcpy(ec_ref_mixer_path, "multi-mic-echo-reference",
                     MIXER_PATH_MAX_LENGTH);
 
@@ -2972,14 +2971,6 @@
     list_init(&operator_info_list);
     list_init(&app_type_entry_list);
 
-    if(audio_extn_is_concurrent_capture_enabled())
-        AUDIO_DEVICE_IN_ALL_CODEC_BACKEND = (AUDIO_DEVICE_IN_BUILTIN_MIC | \
-            AUDIO_DEVICE_IN_BACK_MIC | AUDIO_DEVICE_IN_VOICE_CALL) & ~AUDIO_DEVICE_BIT_IN;
-    else
-        AUDIO_DEVICE_IN_ALL_CODEC_BACKEND = (AUDIO_DEVICE_IN_BUILTIN_MIC | \
-            AUDIO_DEVICE_IN_BACK_MIC | AUDIO_DEVICE_IN_WIRED_HEADSET | \
-            AUDIO_DEVICE_IN_VOICE_CALL) & ~AUDIO_DEVICE_BIT_IN;
-
     adev->snd_card = audio_extn_utils_open_snd_mixer(&adev->mixer);
     if (adev->snd_card < 0) {
         ALOGE("%s: Unable to find correct sound card", __func__);
@@ -4954,14 +4945,16 @@
                  usecase = node_to_item(node, struct audio_usecase, list);
 
                  if (usecase->stream.out && is_offload_usecase(usecase->id) &&
-                    (usecase->stream.out->devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
-                    usecase->stream.out->devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) &&
-                    OUTPUT_SAMPLING_RATE_44100 == usecase->stream.out->sample_rate) {
+                     (compare_device_type(&usecase->stream.out->device_list,
+                                        AUDIO_DEVICE_OUT_WIRED_HEADPHONE) ||
+                     compare_device_type(&usecase->stream.out->device_list,
+                                         AUDIO_DEVICE_OUT_WIRED_HEADSET)) &&
+                     OUTPUT_SAMPLING_RATE_44100 == usecase->stream.out->sample_rate) {
                          ALOGD("%s:napb: triggering dynamic device switch for usecase %d, %s"
                                " stream %p, device (%u)", __func__, usecase->id,
                                use_case_table[usecase->id],
                                (void*) usecase->stream.out,
-                               usecase->stream.out->devices);
+                               get_device_types(&usecase->stream.out->device_list));
                          select_devices(platform->adev, usecase->id);
                  }
             }
@@ -4987,14 +4980,14 @@
     return ret;
 }
 
-int codec_device_supports_native_playback(audio_devices_t out_device)
+int codec_device_supports_native_playback(struct listnode *out_devices)
 {
     int ret = false;
 
-    if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
-        out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET ||
-        out_device & AUDIO_DEVICE_OUT_LINE ||
-        out_device & AUDIO_DEVICE_OUT_USB_HEADSET)
+    if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_WIRED_HEADPHONE) ||
+        compare_device_type(out_devices, AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+        compare_device_type(out_devices, AUDIO_DEVICE_OUT_LINE) ||
+        compare_device_type(out_devices, AUDIO_DEVICE_OUT_USB_HEADSET))
         ret = true;
 
     return ret;
@@ -5072,7 +5065,7 @@
     if (voice_is_in_call(my_data->adev))
         is_incall_rec_usecase = voice_is_in_call_rec_stream(usecase->stream.in);
 
-    if (usecase->devices & AUDIO_DEVICE_OUT_BUS)
+    if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS))
         is_bus_dev_usecase = true;
 
     if (usecase->type == PCM_PLAYBACK)
@@ -5155,7 +5148,7 @@
         /* Notify device change info to effect clients registered */
         if (usecase->type == PCM_PLAYBACK) {
             audio_extn_gef_notify_device_config(
-                    usecase->stream.out->devices,
+                    &usecase->stream.out->device_list,
                     usecase->stream.out->channel_mask,
                     sample_rate,
                     acdb_dev_id,
@@ -5937,7 +5930,7 @@
     struct audio_device *adev = my_data->adev;
     audio_mode_t mode = adev->mode;
     snd_device_t snd_device = SND_DEVICE_NONE;
-    audio_devices_t devices = out->devices;
+    struct listnode devices;
     unsigned int sample_rate = out->sample_rate;
     int na_mode = platform_get_native_support();
     struct stream_in *in = adev_get_active_input(adev);
@@ -5948,14 +5941,17 @@
     int controller = -1;
     int stream = -1;
 
-    ALOGV("%s: enter: output devices(%#x)", __func__, devices);
-    if (devices == AUDIO_DEVICE_NONE ||
-        devices & AUDIO_DEVICE_BIT_IN) {
-        ALOGV("%s: Invalid output devices (%#x)", __func__, devices);
+    list_init(&devices);
+    assign_devices(&devices, &out->device_list);
+
+    ALOGV("%s: enter: output devices(%#x)", __func__, get_device_types(&devices));
+    if (list_empty(&devices) ||
+        compare_device_type(&devices, AUDIO_DEVICE_BIT_IN)) {
+        ALOGV("%s: Invalid output devices (%#x)", __func__, get_device_types(&devices));
         goto exit;
     }
 
-    if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+    if (compare_device_type(&devices, AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
         controller = out->extconn.cs.controller;
         stream = out->extconn.cs.stream;
 
@@ -5967,7 +5963,7 @@
         }
     }
 
-    if (popcount(devices) == 2) {
+    if (list_length(&devices) == 2) {
         bool is_active_voice_call = false;
 
         /*
@@ -5980,8 +5976,8 @@
             voice_extn_compress_voip_is_active(adev))
                 is_active_voice_call = true;
 
-        if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
-                        AUDIO_DEVICE_OUT_SPEAKER)) {
+        if (compare_device_type(&devices, AUDIO_DEVICE_OUT_WIRED_HEADPHONE) &&
+            compare_device_type(&devices, AUDIO_DEVICE_OUT_SPEAKER)) {
             if (my_data->external_spk_1)
                 snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1;
             else if (my_data->external_spk_2)
@@ -5993,11 +5989,11 @@
                 snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_HIFI_FILTER;
             else
                 snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
-        } else if (devices == (AUDIO_DEVICE_OUT_LINE |
-                               AUDIO_DEVICE_OUT_SPEAKER)) {
+        } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_LINE) &&
+                   compare_device_type(&devices, AUDIO_DEVICE_OUT_SPEAKER)) {
                 snd_device = SND_DEVICE_OUT_SPEAKER_AND_LINE;
-        } else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET |
-                               AUDIO_DEVICE_OUT_SPEAKER)) {
+        } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_WIRED_HEADSET) &&
+                   compare_device_type(&devices, AUDIO_DEVICE_OUT_SPEAKER)) {
             if (audio_extn_get_anc_enabled()) {
                 if (audio_extn_should_use_fb_anc()) {
                     if (is_active_voice_call)
@@ -6023,19 +6019,19 @@
                 else
                     snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
             }
-        } else if (devices == (AUDIO_DEVICE_OUT_LINE |
-                               AUDIO_DEVICE_OUT_SPEAKER)) {
+        } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_LINE) &&
+                   compare_device_type(&devices, AUDIO_DEVICE_OUT_SPEAKER)) {
             snd_device = SND_DEVICE_OUT_SPEAKER_AND_LINE;
-        } else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
-                               AUDIO_DEVICE_OUT_SPEAKER_SAFE) ||
-                   devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET |
-                               AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
+        } else if ((compare_device_type(&devices, AUDIO_DEVICE_OUT_WIRED_HEADPHONE) &&
+                    compare_device_type(&devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) ||
+                   (compare_device_type(&devices, AUDIO_DEVICE_OUT_WIRED_HEADSET) &&
+                    compare_device_type(&devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE))) {
             snd_device = SND_DEVICE_OUT_SPEAKER_SAFE_AND_HEADPHONES;
-        } else if (devices == (AUDIO_DEVICE_OUT_LINE |
-                               AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
+        } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_LINE) &&
+                   compare_device_type(&devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
             snd_device = SND_DEVICE_OUT_SPEAKER_SAFE_AND_LINE;
-        } else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL |
-                               AUDIO_DEVICE_OUT_SPEAKER)) {
+        } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
+                   compare_device_type(&devices, AUDIO_DEVICE_OUT_SPEAKER)) {
             switch(my_data->ext_disp[controller][stream].type) {
                 case EXT_DISPLAY_TYPE_HDMI:
                     snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI;
@@ -6049,22 +6045,22 @@
                           my_data->ext_disp[controller][stream].type);
                     goto exit;
             }
-        } else if (devices == (AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
-                               AUDIO_DEVICE_OUT_SPEAKER)) {
+        } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET) &&
+                   compare_device_type(&devices, AUDIO_DEVICE_OUT_SPEAKER)) {
             snd_device = SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET;
-        } else if ((devices == (AUDIO_DEVICE_OUT_USB_DEVICE |
-                               AUDIO_DEVICE_OUT_SPEAKER)) ||
-                   (devices == (AUDIO_DEVICE_OUT_USB_HEADSET |
-                               AUDIO_DEVICE_OUT_SPEAKER))) {
+        } else if ((compare_device_type(&devices, AUDIO_DEVICE_OUT_USB_DEVICE) &&
+                    compare_device_type(&devices, AUDIO_DEVICE_OUT_SPEAKER)) ||
+                   (compare_device_type(&devices, AUDIO_DEVICE_OUT_USB_HEADSET) &&
+                    compare_device_type(&devices, AUDIO_DEVICE_OUT_SPEAKER))) {
             snd_device = SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET;
-        } else if ((devices & AUDIO_DEVICE_OUT_SPEAKER) &&
-                   (devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
+        } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_SPEAKER) &&
+                   is_a2dp_out_device_type(&devices)) {
             snd_device = SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP;
-        }  else if ((devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE) &&
-                   (devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
+        }  else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE) &&
+                   is_a2dp_out_device_type(&devices)) {
             snd_device = SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP;
-        } else if ((devices & AUDIO_DEVICE_OUT_ALL_SCO) &&
-                   ((devices & ~AUDIO_DEVICE_OUT_ALL_SCO) == AUDIO_DEVICE_OUT_SPEAKER)) {
+        } else if (is_sco_out_device_type(&devices) &&
+                   compare_device_type(&devices, AUDIO_DEVICE_OUT_SPEAKER)) {
             if (my_data->is_wsa_speaker) {
                 if (adev->swb_speech_mode != SPEECH_MODE_INVALID)
                     snd_device = SND_DEVICE_OUT_SPEAKER_WSA_AND_BT_SCO_SWB;
@@ -6080,21 +6076,21 @@
                             SND_DEVICE_OUT_SPEAKER_AND_BT_SCO_WB :
                             SND_DEVICE_OUT_SPEAKER_AND_BT_SCO;
             }
-        } else if ((devices & AUDIO_DEVICE_OUT_ALL_SCO) &&
-                         ((devices & ~AUDIO_DEVICE_OUT_ALL_SCO) == AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
+        } else if (is_sco_out_device_type(&devices) &&
+                         compare_device_type(&devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
             if (adev->swb_speech_mode != SPEECH_MODE_INVALID)
                 snd_device = SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_SCO_SWB;
             else
                 snd_device = adev->bt_wb_speech_enabled ?
                         SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_SCO_WB :
                         SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_SCO;
-        } else if ((devices == (AUDIO_DEVICE_OUT_USB_DEVICE |
-                               AUDIO_DEVICE_OUT_SPEAKER_SAFE)) ||
-                (devices == (AUDIO_DEVICE_OUT_USB_HEADSET |
-                                               AUDIO_DEVICE_OUT_SPEAKER_SAFE))) {
+        } else if ((compare_device_type(&devices, AUDIO_DEVICE_OUT_USB_DEVICE) &&
+                    compare_device_type(&devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) ||
+                   (compare_device_type(&devices, AUDIO_DEVICE_OUT_USB_HEADSET) &&
+                    compare_device_type(&devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE))) {
             snd_device = SND_DEVICE_OUT_SPEAKER_SAFE_AND_USB_HEADSET;
         } else {
-            ALOGE("%s: Invalid combo device(%#x)", __func__, devices);
+            ALOGE("%s: Invalid combo device(%#x)", __func__, get_device_types(&devices));
             goto exit;
         }
         if (snd_device != SND_DEVICE_NONE) {
@@ -6102,8 +6098,8 @@
         }
     }
 
-    if (popcount(devices) != 1) {
-        ALOGE("%s: Invalid output devices(%#x)", __func__, devices);
+    if (list_length(&devices) != 1) {
+        ALOGE("%s: Invalid output devices(%#x)", __func__, get_device_types(&devices));
         goto exit;
     }
 
@@ -6112,15 +6108,15 @@
         voice_extn_compress_voip_is_active(adev) ||
         adev->enable_voicerx ||
         audio_extn_hfp_is_active(adev)) {
-        if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
-            devices & AUDIO_DEVICE_OUT_WIRED_HEADSET ||
-            devices & AUDIO_DEVICE_OUT_LINE) {
+        if (compare_device_type(&devices, AUDIO_DEVICE_OUT_WIRED_HEADPHONE) ||
+            compare_device_type(&devices, AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+            compare_device_type(&devices, AUDIO_DEVICE_OUT_LINE)) {
             if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
                 !voice_extn_compress_voip_is_active(adev)) {
                 switch (adev->voice.tty_mode) {
                 case TTY_MODE_FULL:
                     if (audio_extn_is_concurrent_capture_enabled() &&
-                         (devices & AUDIO_DEVICE_OUT_WIRED_HEADSET)) {
+                         compare_device_type(&devices, AUDIO_DEVICE_OUT_WIRED_HEADSET)) {
                         //Separate backend is added for headset-mic as part of concurrent capture
                         snd_device = SND_DEVICE_OUT_VOICE_TTY_FULL_HEADSET;
                     } else {
@@ -6129,7 +6125,7 @@
                     break;
                 case TTY_MODE_VCO:
                     if (audio_extn_is_concurrent_capture_enabled() &&
-                         (devices & AUDIO_DEVICE_OUT_WIRED_HEADSET)) {
+                         compare_device_type(&devices, AUDIO_DEVICE_OUT_WIRED_HEADSET)) {
                         //Separate backend is added for headset-mic as part of concurrent capture
                         snd_device = SND_DEVICE_OUT_VOICE_TTY_VCO_HEADSET;
                     } else {
@@ -6143,7 +6139,7 @@
                     ALOGE("%s: Invalid TTY mode (%#x)",
                           __func__, adev->voice.tty_mode);
                 }
-            } else if (devices & AUDIO_DEVICE_OUT_LINE) {
+            } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_LINE)) {
                 snd_device = SND_DEVICE_OUT_VOICE_LINE;
             } else if (audio_extn_get_anc_enabled()) {
                 if (audio_extn_should_use_fb_anc())
@@ -6151,15 +6147,14 @@
                 else
                     snd_device = SND_DEVICE_OUT_VOICE_ANC_HEADSET;
             } else if (audio_extn_is_concurrent_capture_enabled() &&
-                        (devices & AUDIO_DEVICE_OUT_WIRED_HEADSET)) {
+                        compare_device_type(&devices, AUDIO_DEVICE_OUT_WIRED_HEADSET)) {
                 //Separate backend is added for headset-mic as part of concurrent capture
                 snd_device = SND_DEVICE_OUT_VOICE_HEADSET;
             } else {
                 snd_device = SND_DEVICE_OUT_VOICE_HEADPHONES;
             }
-        } else if (devices &
-                    (AUDIO_DEVICE_OUT_USB_DEVICE |
-                     AUDIO_DEVICE_OUT_USB_HEADSET)) {
+        } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_USB_DEVICE) ||
+                   compare_device_type(&devices, AUDIO_DEVICE_OUT_USB_HEADSET)) {
             if (voice_is_in_call(adev)) {
                 switch (adev->voice.tty_mode) {
                     case TTY_MODE_FULL:
@@ -6184,14 +6179,15 @@
                                  SND_DEVICE_OUT_VOICE_USB_HEADSET :
                                  SND_DEVICE_OUT_VOICE_USB_HEADPHONES;
             }
-        } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
+        } else if (is_sco_out_device_type(&devices)) {
             if (adev->swb_speech_mode != SPEECH_MODE_INVALID)
                 snd_device = SND_DEVICE_OUT_BT_SCO_SWB;
             else if (adev->bt_wb_speech_enabled)
                 snd_device = SND_DEVICE_OUT_BT_SCO_WB;
             else
                 snd_device = SND_DEVICE_OUT_BT_SCO;
-        } else if (devices & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
+        } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_SPEAKER) ||
+                   compare_device_type(&devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
             if (my_data->is_vbat_speaker || my_data->is_bcl_speaker) {
                 if (hw_info_is_stereo_spkr(my_data->hw_info)) {
                     if (my_data->mono_speaker == SPKR_1)
@@ -6222,12 +6218,12 @@
                 else
                     snd_device = SND_DEVICE_OUT_VOICE_SPEAKER;
             }
-        } else if (devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
+        } else if (is_a2dp_out_device_type(&devices)) {
             snd_device = SND_DEVICE_OUT_BT_A2DP;
-        } else if (devices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET ||
-                   devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
+        } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET) ||
+                   compare_device_type(&devices, AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET)) {
             snd_device = SND_DEVICE_OUT_USB_HEADSET;
-        } else if ((devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
+        } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
                    adev->dp_allowed_for_voice) {
             switch(my_data->ext_disp[controller][stream].type) {
                 case EXT_DISPLAY_TYPE_DP:
@@ -6239,9 +6235,9 @@
                            my_data->ext_disp[controller][stream].type);
                     goto exit;
             }
-        } else if (devices & AUDIO_DEVICE_OUT_FM_TX) {
+        } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_FM_TX)) {
             snd_device = SND_DEVICE_OUT_TRANSMISSION_FM;
-        } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
+        } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_EARPIECE)) {
             if(adev->voice.hac)
                 snd_device = SND_DEVICE_OUT_VOICE_HAC_HANDSET;
             else if (is_operator_tmus())
@@ -6250,9 +6246,9 @@
                 snd_device = SND_DEVICE_OUT_ANC_HANDSET;
             else
                 snd_device = SND_DEVICE_OUT_VOICE_HANDSET;
-        } else if (devices & AUDIO_DEVICE_OUT_TELEPHONY_TX) {
+        } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
             snd_device = SND_DEVICE_OUT_VOICE_TX;
-        } else if (devices & AUDIO_DEVICE_OUT_HEARING_AID) {
+        } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_HEARING_AID)) {
             snd_device = SND_DEVICE_OUT_VOICE_HEARING_AID;
         }
 
@@ -6261,16 +6257,16 @@
         }
     }
 
-    if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
-        devices & AUDIO_DEVICE_OUT_WIRED_HEADSET ||
-        devices & AUDIO_DEVICE_OUT_LINE) {
+    if (compare_device_type(&devices, AUDIO_DEVICE_OUT_WIRED_HEADPHONE) ||
+        compare_device_type(&devices, AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+        compare_device_type(&devices, AUDIO_DEVICE_OUT_LINE)) {
         if (OUTPUT_SAMPLING_RATE_44100 == sample_rate &&
             NATIVE_AUDIO_MODE_SRC == na_mode &&
             !audio_extn_get_anc_enabled()) {
 
             snd_device = SND_DEVICE_OUT_HEADPHONES_44_1;
 
-        } else if (devices & AUDIO_DEVICE_OUT_WIRED_HEADSET
+        } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_WIRED_HEADSET)
             && audio_extn_get_anc_enabled()) {
                 if (audio_extn_should_use_fb_anc())
                     snd_device = SND_DEVICE_OUT_ANC_FB_HEADSET;
@@ -6288,15 +6284,15 @@
         } else if (audio_extn_is_hifi_filter_enabled(adev, out, snd_device,
              my_data->codec_variant, channel_count, 1)) {
                 snd_device = SND_DEVICE_OUT_HEADPHONES_HIFI_FILTER;
-        } else if (devices & AUDIO_DEVICE_OUT_LINE) {
+        } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_LINE)) {
                 snd_device = SND_DEVICE_OUT_LINE;
         } else
                 snd_device = SND_DEVICE_OUT_HEADPHONES;
-    } else if (devices & AUDIO_DEVICE_OUT_LINE) {
+    } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_LINE)) {
         snd_device = SND_DEVICE_OUT_LINE;
-    } else if (devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
+    } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
         snd_device = SND_DEVICE_OUT_SPEAKER_SAFE;
-    } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
+    } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_SPEAKER)) {
         if (my_data->external_spk_1)
             snd_device = SND_DEVICE_OUT_SPEAKER_EXTERNAL_1;
         else if (my_data->external_spk_2)
@@ -6319,16 +6315,16 @@
             snd_device = SND_DEVICE_OUT_SPEAKER_WSA;
         else
             snd_device = SND_DEVICE_OUT_SPEAKER;
-    } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
+    } else if (is_sco_out_device_type(&devices)) {
         if (adev->swb_speech_mode != SPEECH_MODE_INVALID)
                 snd_device = SND_DEVICE_OUT_BT_SCO_SWB;
         else if (adev->bt_wb_speech_enabled)
             snd_device = SND_DEVICE_OUT_BT_SCO_WB;
         else
             snd_device = SND_DEVICE_OUT_BT_SCO;
-    } else if (devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
+    } else if (is_a2dp_out_device_type(&devices)) {
         snd_device = SND_DEVICE_OUT_BT_A2DP;
-    } else if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+    } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
             switch(my_data->ext_disp[controller][stream].type) {
                 case EXT_DISPLAY_TYPE_HDMI:
                     snd_device = SND_DEVICE_OUT_HDMI;
@@ -6342,37 +6338,36 @@
                           my_data->ext_disp[controller][stream].type);
                     goto exit;
             }
-    } else if (devices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET ||
-               devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
+    } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET) ||
+               compare_device_type(&devices, AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET)) {
         ALOGD("%s: setting USB hadset channel capability(2) for Proxy", __func__);
         snd_device = SND_DEVICE_OUT_USB_HEADSET;
         audio_extn_set_afe_proxy_channel_mixer(adev, 2, snd_device);
-    } else if (devices &
-                (AUDIO_DEVICE_OUT_USB_DEVICE |
-                 AUDIO_DEVICE_OUT_USB_HEADSET)) {
+    } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_USB_DEVICE) ||
+               compare_device_type(&devices, AUDIO_DEVICE_OUT_USB_HEADSET)) {
         if (audio_extn_qdsp_supported_usb())
             snd_device = SND_DEVICE_OUT_USB_HEADSET_SPEC;
         else if (audio_extn_usb_is_capture_supported())
             snd_device = SND_DEVICE_OUT_USB_HEADSET;
         else
             snd_device = SND_DEVICE_OUT_USB_HEADPHONES;
-    } else if (devices & AUDIO_DEVICE_OUT_FM_TX) {
+    } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_FM_TX)) {
         snd_device = SND_DEVICE_OUT_TRANSMISSION_FM;
-    } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
+    } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_EARPIECE)) {
         /*HAC support for voice-ish audio (eg visual voicemail)*/
         if(adev->voice.hac)
             snd_device = SND_DEVICE_OUT_VOICE_HAC_HANDSET;
         else
             snd_device = SND_DEVICE_OUT_HANDSET;
-    } else if (devices & AUDIO_DEVICE_OUT_PROXY) {
+    } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_PROXY)) {
         channel_count = audio_extn_get_afe_proxy_channel_count();
         ALOGD("%s: setting sink capability(%d) for Proxy", __func__, channel_count);
         snd_device = SND_DEVICE_OUT_AFE_PROXY;
         audio_extn_set_afe_proxy_channel_mixer(adev, channel_count, snd_device);
-    } else if (devices & AUDIO_DEVICE_OUT_BUS) {
+    } else if (compare_device_type(&devices, AUDIO_DEVICE_OUT_BUS)) {
         snd_device = audio_extn_auto_hal_get_output_snd_device(adev, out->usecase);
     } else {
-        ALOGE("%s: Unknown device(s) %#x", __func__, devices);
+        ALOGE("%s: Unknown device(s) %#x", __func__, get_device_types(&devices));
     }
 exit:
     ALOGV("%s: exit: snd_device(%s)", __func__, device_table[snd_device]);
@@ -6381,13 +6376,13 @@
 
 static snd_device_t get_snd_device_for_voice_comm_ecns_enabled(struct platform_data *my_data,
                                                   struct stream_in *in,
-                                                  audio_devices_t out_device __unused,
-                                                  audio_devices_t in_device)
+                                                  struct listnode *out_devices __unused,
+                                                  struct listnode *in_devices)
 {
     struct audio_device *adev = my_data->adev;
     snd_device_t snd_device = SND_DEVICE_NONE;
 
-    if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+    if (compare_device_type(in_devices, AUDIO_DEVICE_IN_BACK_MIC)) {
         if (my_data->fluence_in_spkr_mode) {
             if ((my_data->fluence_type & FLUENCE_QUAD_MIC) &&
                 (my_data->source_mic_type & SOURCE_QUAD_MIC)) {
@@ -6409,7 +6404,7 @@
             snd_device = my_data->fluence_sb_enabled ?
                              SND_DEVICE_IN_SPEAKER_MIC_SB
                              : SND_DEVICE_IN_SPEAKER_MIC;
-    } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+    } else if (compare_device_type(in_devices, AUDIO_DEVICE_IN_BUILTIN_MIC)) {
         if ((my_data->fluence_type & FLUENCE_TRI_MIC) &&
             (my_data->source_mic_type & SOURCE_THREE_MIC)) {
             snd_device = SND_DEVICE_IN_HANDSET_TMIC_AEC_NS;
@@ -6424,7 +6419,7 @@
             snd_device = my_data->fluence_sb_enabled ?
                              SND_DEVICE_IN_HANDSET_MIC_SB
                              : SND_DEVICE_IN_HANDSET_MIC;
-    } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+    } else if (compare_device_type(in_devices, AUDIO_DEVICE_IN_WIRED_HEADSET)) {
         snd_device = SND_DEVICE_IN_HEADSET_MIC;
     }
     in->enable_ec_port = true;
@@ -6434,14 +6429,14 @@
 
 static snd_device_t get_snd_device_for_voice_comm_ecns_disabled(struct platform_data *my_data,
                                                   struct stream_in *in,
-                                                  audio_devices_t out_device,
-                                                  audio_devices_t in_device)
+                                                  struct listnode *out_devices,
+                                                  struct listnode *in_devices)
 {
     struct audio_device *adev = my_data->adev;
     snd_device_t snd_device = SND_DEVICE_NONE;
 
     if (in != NULL && in->enable_aec && in->enable_ns) {
-        if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+        if (compare_device_type(in_devices, AUDIO_DEVICE_IN_BACK_MIC)) {
             if (my_data->fluence_in_spkr_mode) {
                 if ((my_data->fluence_type & FLUENCE_QUAD_MIC) &&
                     (my_data->source_mic_type & SOURCE_QUAD_MIC)) {
@@ -6464,7 +6459,7 @@
                 snd_device = my_data->fluence_sb_enabled ?
                                  SND_DEVICE_IN_SPEAKER_MIC_AEC_NS_SB
                                  : SND_DEVICE_IN_SPEAKER_MIC_AEC_NS;
-        } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+        } else if (compare_device_type(in_devices, AUDIO_DEVICE_IN_BUILTIN_MIC)) {
             if ((my_data->fluence_type & FLUENCE_TRI_MIC) &&
                 (my_data->source_mic_type & SOURCE_THREE_MIC)) {
                 snd_device = SND_DEVICE_IN_HANDSET_TMIC_AEC_NS;
@@ -6480,13 +6475,14 @@
                 snd_device = my_data->fluence_sb_enabled ?
                                  SND_DEVICE_IN_HANDSET_MIC_AEC_NS_SB
                                  : SND_DEVICE_IN_HANDSET_MIC_AEC_NS;
-        } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+        } else if (compare_device_type(in_devices, AUDIO_DEVICE_IN_WIRED_HEADSET)) {
             snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
-        } else if (audio_extn_usb_connected(NULL) && audio_is_usb_in_device(in_device | AUDIO_DEVICE_BIT_IN)) {
+        } else if (audio_extn_usb_connected(NULL) &&
+                   is_usb_in_device_type(in_devices)) {
             snd_device = SND_DEVICE_IN_USB_HEADSET_MIC_AEC;
         }
     } else if (in != NULL && in->enable_aec) {
-        if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+        if (compare_device_type(in_devices, AUDIO_DEVICE_IN_BACK_MIC)) {
             if (my_data->fluence_in_spkr_mode) {
                 if ((my_data->fluence_type & FLUENCE_QUAD_MIC) &&
                     (my_data->source_mic_type & SOURCE_QUAD_MIC)) {
@@ -6509,7 +6505,7 @@
                 snd_device = my_data->fluence_sb_enabled ?
                                  SND_DEVICE_IN_SPEAKER_MIC_AEC_SB
                                  : SND_DEVICE_IN_SPEAKER_MIC_AEC;
-        } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+        } else if (compare_device_type(in_devices, AUDIO_DEVICE_IN_BUILTIN_MIC)) {
             if ((my_data->fluence_type & FLUENCE_TRI_MIC) &&
                 (my_data->source_mic_type & SOURCE_THREE_MIC)) {
                 snd_device = SND_DEVICE_IN_HANDSET_TMIC_AEC;
@@ -6523,13 +6519,13 @@
                 adev->acdb_settings |= DMIC_FLAG;
             } else
                 snd_device = SND_DEVICE_IN_HANDSET_MIC_AEC;
-        } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+        } else if (compare_device_type(in_devices, AUDIO_DEVICE_IN_WIRED_HEADSET)) {
             snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
-        } else if (audio_extn_usb_connected(NULL) && audio_is_usb_in_device(in_device | AUDIO_DEVICE_BIT_IN)) {
+        } else if (audio_extn_usb_connected(NULL) && is_usb_in_device_type(in_devices)) {
             snd_device = SND_DEVICE_IN_USB_HEADSET_MIC_AEC;
         }
     } else if (in != NULL && in->enable_ns) {
-        if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+        if (compare_device_type(in_devices, AUDIO_DEVICE_IN_BACK_MIC)) {
             if (my_data->fluence_in_spkr_mode) {
                 if ((my_data->fluence_type & FLUENCE_QUAD_MIC) &&
                     (my_data->source_mic_type & SOURCE_QUAD_MIC)) {
@@ -6552,7 +6548,7 @@
                 snd_device = my_data->fluence_sb_enabled ?
                                  SND_DEVICE_IN_SPEAKER_MIC_NS_SB
                                  : SND_DEVICE_IN_SPEAKER_MIC_NS;
-        } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+        } else if (compare_device_type(in_devices, AUDIO_DEVICE_IN_BUILTIN_MIC)) {
             if ((my_data->fluence_type & FLUENCE_TRI_MIC) &&
                 (my_data->source_mic_type & SOURCE_THREE_MIC)) {
                 snd_device = SND_DEVICE_IN_HANDSET_TMIC_NS;
@@ -6566,42 +6562,45 @@
                 adev->acdb_settings |= DMIC_FLAG;
             } else
                 snd_device = SND_DEVICE_IN_HANDSET_MIC_NS;
-        } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+        } else if (compare_device_type(in_devices, AUDIO_DEVICE_IN_WIRED_HEADSET)) {
             snd_device = SND_DEVICE_IN_HEADSET_MIC_FLUENCE;
         }
-        platform_set_echo_reference(adev, false, out_device);
+        platform_set_echo_reference(adev, false, out_devices);
     } else
-        platform_set_echo_reference(adev, false, out_device);
+        platform_set_echo_reference(adev, false, out_devices);
 
     return snd_device;
 }
 
 static snd_device_t get_snd_device_for_voice_comm(struct platform_data *my_data,
                                                   struct stream_in *in,
-                                                  audio_devices_t out_device,
-                                                  audio_devices_t in_device)
+                                                  struct listnode *out_devices,
+                                                  struct listnode *in_devices)
 {
     if(voice_extn_is_dynamic_ecns_enabled())
-        return get_snd_device_for_voice_comm_ecns_enabled(my_data, in, out_device, in_device);
+        return get_snd_device_for_voice_comm_ecns_enabled(my_data, in, out_devices, in_devices);
     else
-        return get_snd_device_for_voice_comm_ecns_disabled(my_data, in, out_device, in_device);
+        return get_snd_device_for_voice_comm_ecns_disabled(my_data, in, out_devices, in_devices);
 }
 
 snd_device_t platform_get_input_snd_device(void *platform,
                                            struct stream_in *in,
-                                           audio_devices_t out_device)
+                                           struct listnode *out_devices)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
     struct audio_device *adev = my_data->adev;
     audio_mode_t mode = adev->mode;
     snd_device_t snd_device = SND_DEVICE_NONE;
+    struct listnode in_devices;
+    char *address = "";
 
     if (in == NULL)
         in = adev_get_active_input(adev);
 
     audio_source_t source = (in == NULL) ? AUDIO_SOURCE_DEFAULT : in->source;
-    audio_devices_t in_device =
-        ((in == NULL) ? AUDIO_DEVICE_NONE : in->device) & ~AUDIO_DEVICE_BIT_IN;
+    list_init(&in_devices);
+    if (in != NULL)
+        assign_devices(&in_devices, &in->device_list);
     audio_channel_mask_t channel_mask = (in == NULL) ? AUDIO_CHANNEL_IN_MONO : in->channel_mask;
     int channel_count = audio_channel_count_from_in_mask(channel_mask);
     int str_bitwidth = (in == NULL) ? CODEC_BACKEND_DEFAULT_BIT_WIDTH : in->bit_width;
@@ -6610,18 +6609,19 @@
     audio_usecase_t uc_id = (in == NULL) ? USECASE_AUDIO_RECORD : in->usecase;
 
     ALOGV("%s: enter: out_device(%#x) in_device(%#x) channel_count (%d) channel_mask (0x%x)",
-          __func__, out_device, in_device, channel_count, channel_mask);
+          __func__, get_device_types(out_devices), get_device_types(&in_devices),
+          channel_count, channel_mask);
     if (my_data->external_mic) {
-        if ((out_device != AUDIO_DEVICE_NONE) && ((mode == AUDIO_MODE_IN_CALL) ||
+        if (!list_empty(out_devices) && ((mode == AUDIO_MODE_IN_CALL) ||
             voice_check_voicecall_usecases_active(adev) ||
             voice_extn_compress_voip_is_active(adev) ||
             audio_extn_hfp_is_active(adev))) {
-            if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
-               out_device & AUDIO_DEVICE_OUT_EARPIECE ||
-               out_device & AUDIO_DEVICE_OUT_SPEAKER )
+            if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_WIRED_HEADPHONE) ||
+               compare_device_type(out_devices, AUDIO_DEVICE_OUT_EARPIECE) ||
+               compare_device_type(out_devices, AUDIO_DEVICE_OUT_SPEAKER))
                 snd_device = SND_DEVICE_IN_HANDSET_MIC_EXTERNAL;
-        } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC ||
-                   in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+        } else if (compare_device_type(&in_devices, AUDIO_DEVICE_IN_BUILTIN_MIC) ||
+                   compare_device_type(&in_devices, AUDIO_DEVICE_IN_BACK_MIC)) {
             snd_device = SND_DEVICE_IN_HANDSET_MIC_EXTERNAL;
         }
     }
@@ -6629,15 +6629,15 @@
     if (snd_device != AUDIO_DEVICE_NONE)
         goto exit;
 
-    if ((out_device != AUDIO_DEVICE_NONE) && ((mode == AUDIO_MODE_IN_CALL) ||
+    if (!list_empty(out_devices) && ((mode == AUDIO_MODE_IN_CALL) ||
         voice_check_voicecall_usecases_active(adev) ||
         voice_extn_compress_voip_is_active(adev) ||
         audio_extn_hfp_is_active(adev))) {
         if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
             !voice_extn_compress_voip_is_active(adev)) {
-            if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
-                out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET ||
-                out_device & AUDIO_DEVICE_OUT_LINE) {
+            if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_WIRED_HEADPHONE) ||
+                compare_device_type(out_devices, AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+                compare_device_type(out_devices, AUDIO_DEVICE_OUT_LINE)) {
                 switch (adev->voice.tty_mode) {
                     case TTY_MODE_FULL:
                         snd_device = SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC;
@@ -6652,9 +6652,8 @@
                         ALOGE("%s: Invalid TTY mode (%#x)", __func__, adev->voice.tty_mode);
                 }
                 goto exit;
-            } else if (out_device &
-                        (AUDIO_DEVICE_OUT_USB_DEVICE |
-                         AUDIO_DEVICE_OUT_USB_HEADSET)) {
+            } else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_USB_DEVICE) ||
+                       compare_device_type(out_devices, AUDIO_DEVICE_OUT_USB_HEADSET)) {
                 switch (adev->voice.tty_mode) {
                     case TTY_MODE_FULL:
                         snd_device = SND_DEVICE_IN_VOICE_TTY_FULL_USB_MIC;
@@ -6672,10 +6671,10 @@
                 goto exit;
             }
         }
-        if (out_device & AUDIO_DEVICE_OUT_EARPIECE ||
-            out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
-                out_device & AUDIO_DEVICE_OUT_LINE) {
-            if (out_device & AUDIO_DEVICE_OUT_EARPIECE &&
+        if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_EARPIECE) ||
+            compare_device_type(out_devices, AUDIO_DEVICE_OUT_WIRED_HEADPHONE) ||
+            compare_device_type(out_devices, AUDIO_DEVICE_OUT_LINE)) {
+            if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_EARPIECE) &&
                 audio_extn_should_use_handset_anc(channel_count)) {
                 if ((my_data->fluence_type != FLUENCE_NONE) &&
                     (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
@@ -6688,7 +6687,7 @@
             } else if (my_data->fluence_type == FLUENCE_NONE ||
                 (my_data->fluence_in_voice_call == false &&
                  my_data->fluence_in_hfp_call == false)) {
-                 if (out_device & AUDIO_DEVICE_OUT_LINE &&
+                 if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_LINE) &&
                      audio_extn_hfp_is_active(adev)) {
                      snd_device = my_data->fluence_sb_enabled ?
                                       SND_DEVICE_IN_VOICE_SPEAKER_MIC_SB
@@ -6699,7 +6698,7 @@
                                      : SND_DEVICE_IN_HANDSET_MIC;
                  }
                  if (audio_extn_hfp_is_active(adev))
-                     platform_set_echo_reference(adev, true, out_device);
+                     platform_set_echo_reference(adev, true, out_devices);
             } else {
                 if ((my_data->fluence_type & FLUENCE_TRI_MIC) &&
                     (my_data->source_mic_type & SOURCE_THREE_MIC)) {
@@ -6714,11 +6713,11 @@
                     adev->acdb_settings |= DMIC_FLAG;
                 }
             }
-        } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+        } else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_WIRED_HEADSET)) {
             snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC;
             if (audio_extn_hfp_is_active(adev))
-                platform_set_echo_reference(adev, true, out_device);
-        } else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) {
+                platform_set_echo_reference(adev, true, out_devices);
+        } else if (is_sco_out_device_type(out_devices)) {
             if (adev->swb_speech_mode != SPEECH_MODE_INVALID) {
                 if (adev->bluetooth_nrec)
                     snd_device = SND_DEVICE_IN_BT_SCO_MIC_SWB_NREC;
@@ -6735,7 +6734,7 @@
                 else
                     snd_device = SND_DEVICE_IN_BT_SCO_MIC;
             }
-        } else if ((out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
+        } else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
                    adev->dp_allowed_for_voice) {
             if (audio_extn_usb_is_capture_supported())
                 snd_device = SND_DEVICE_IN_VOICE_USB_HEADSET_MIC;
@@ -6745,11 +6744,11 @@
                                  : SND_DEVICE_IN_HANDSET_MIC;
 
             if (voice_is_in_call(adev))
-                platform_set_echo_reference(adev, true, out_device);
-        } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER ||
-                   out_device & AUDIO_DEVICE_OUT_SPEAKER_SAFE ||
-                   out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
-                   out_device & AUDIO_DEVICE_OUT_LINE) {
+                platform_set_echo_reference(adev, true, out_devices);
+        } else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_SPEAKER) ||
+                   compare_device_type(out_devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE) ||
+                   compare_device_type(out_devices, AUDIO_DEVICE_OUT_WIRED_HEADPHONE) ||
+                   compare_device_type(out_devices, AUDIO_DEVICE_OUT_LINE)) {
             if (my_data->fluence_type != FLUENCE_NONE &&
                 (my_data->fluence_in_voice_call ||
                  my_data->fluence_in_hfp_call) &&
@@ -6772,24 +6771,23 @@
                                         : SND_DEVICE_IN_VOICE_SPEAKER_DMIC;
                 }
                 if (audio_extn_hfp_is_active(adev))
-                    platform_set_echo_reference(adev, true, out_device);
+                    platform_set_echo_reference(adev, true, out_devices);
             } else {
                 if (adev->enable_hfp) {
                     snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP;
-                    platform_set_echo_reference(adev, true, out_device);
+                    platform_set_echo_reference(adev, true, out_devices);
                 } else {
                     snd_device = my_data->fluence_sb_enabled ?
                                      SND_DEVICE_IN_VOICE_SPEAKER_MIC_SB
                                      : SND_DEVICE_IN_VOICE_SPEAKER_MIC;
                     if (audio_extn_hfp_is_active(adev))
-                        platform_set_echo_reference(adev, true, out_device);
+                        platform_set_echo_reference(adev, true, out_devices);
                 }
             }
-        } else if (out_device & AUDIO_DEVICE_OUT_TELEPHONY_TX) {
+        } else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
             snd_device = SND_DEVICE_IN_VOICE_RX;
-        } else if (out_device &
-                    (AUDIO_DEVICE_OUT_USB_DEVICE |
-                     AUDIO_DEVICE_OUT_USB_HEADSET)) {
+        } else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_USB_DEVICE) ||
+                   compare_device_type(out_devices, AUDIO_DEVICE_OUT_USB_HEADSET)) {
             if (audio_extn_usb_is_capture_supported()) {
                 snd_device = SND_DEVICE_IN_VOICE_USB_HEADSET_MIC;
             } else if (my_data->fluence_in_voice_call && my_data->fluence_in_spkr_mode) {
@@ -6801,25 +6799,25 @@
             } else {
                 snd_device = SND_DEVICE_IN_HANDSET_MIC;
             }
-        } else if (out_device & AUDIO_DEVICE_OUT_HEARING_AID) {
+        } else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_HEARING_AID)) {
             snd_device = SND_DEVICE_IN_VOICE_HEARING_AID;
         }
     } else if (my_data->use_generic_handset == true &&  //     system prop is enabled
                (my_data->source_mic_type & SOURCE_QUAD_MIC) &&  // AND 4mic is available
-               ((in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) ||    // AND device is buit-in mic or back mic
-                (in_device & AUDIO_DEVICE_IN_BACK_MIC)) &&
+               (compare_device_type(&in_devices, AUDIO_DEVICE_IN_BUILTIN_MIC) ||    // AND device is buit-in mic or back mic
+                compare_device_type(&in_devices, AUDIO_DEVICE_IN_BACK_MIC)) &&
                (my_data->fluence_in_audio_rec == true &&       //  AND fluencepro is enabled
                 my_data->fluence_type & FLUENCE_QUAD_MIC) &&
                (source == AUDIO_SOURCE_CAMCORDER ||           // AND source is cam/mic/unprocessed
                 source == AUDIO_SOURCE_UNPROCESSED ||
                 source == AUDIO_SOURCE_MIC)) {
                 snd_device = SND_DEVICE_IN_HANDSET_GENERIC_QMIC;
-                platform_set_echo_reference(adev, true, out_device);
+                platform_set_echo_reference(adev, true, out_devices);
     } else if (my_data->use_generic_handset == true &&          // System prop is enabled
                (my_data->ambisonic_capture == true) &&          // Enable Ambisonic capture
                (my_data->source_mic_type & SOURCE_QUAD_MIC) &&  // AND 4mic is available
-               ((in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) ||    // AND device is Built-in
-               (in_device & AUDIO_DEVICE_IN_BACK_MIC)) &&       // OR Back-mic
+               (compare_device_type(&in_devices, AUDIO_DEVICE_IN_BUILTIN_MIC) ||    // AND device is Built-in
+                compare_device_type(&in_devices, AUDIO_DEVICE_IN_BACK_MIC)) &&       // OR Back-mic
                (source == AUDIO_SOURCE_MIC ||                   // AND source is MIC for 16bit
                 source == AUDIO_SOURCE_UNPROCESSED ||           // OR unprocessed for 24bit
                 source == AUDIO_SOURCE_CAMCORDER) &&            // OR camera usecase
@@ -6847,8 +6845,8 @@
                     }
                 }
     } else if (source == AUDIO_SOURCE_CAMCORDER) {
-        if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC ||
-            in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+        if (compare_device_type(&in_devices, AUDIO_DEVICE_IN_BUILTIN_MIC) ||
+            compare_device_type(&in_devices, AUDIO_DEVICE_IN_BACK_MIC)) {
             switch (adev->camera_orientation) {
             case CAMERA_BACK_LANDSCAPE:
                 snd_device = SND_DEVICE_IN_CAMCORDER_LANDSCAPE;
@@ -6902,7 +6900,7 @@
            }
        }
     }  else if (source == AUDIO_SOURCE_VOICE_RECOGNITION) {
-        if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+        if (compare_device_type(&in_devices, AUDIO_DEVICE_IN_BUILTIN_MIC)) {
             if (my_data->fluence_in_voice_rec && channel_count == 1) {
                 if ((my_data->fluence_type & FLUENCE_QUAD_MIC) &&
                     (my_data->source_mic_type & SOURCE_QUAD_MIC)) {
@@ -6947,15 +6945,15 @@
                 else
                     snd_device = SND_DEVICE_IN_VOICE_REC_MIC;
             }
-        } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+        } else if (compare_device_type(&in_devices, AUDIO_DEVICE_IN_WIRED_HEADSET)) {
             snd_device = SND_DEVICE_IN_VOICE_REC_HEADSET_MIC;
-        } else if (audio_is_usb_in_device(in_device | AUDIO_DEVICE_BIT_IN)) {
+        } else if (is_usb_in_device_type(&in_devices)) {
             snd_device = fixup_usb_headset_mic_snd_device(platform,
                                       SND_DEVICE_IN_VOICE_RECOG_USB_HEADSET_MIC,
                                       SND_DEVICE_IN_VOICE_RECOG_USB_HEADSET_MULTI_CHANNEL_MIC);
         }
     } else if (source == AUDIO_SOURCE_UNPROCESSED) {
-         if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+         if (compare_device_type(&in_devices, AUDIO_DEVICE_IN_BUILTIN_MIC)) {
              if (((channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK) ||
                  (channel_mask == AUDIO_CHANNEL_IN_STEREO)) &&
                  (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
@@ -6969,40 +6967,43 @@
              } else {
                  snd_device = SND_DEVICE_IN_UNPROCESSED_MIC;
              }
-         } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+         } else if (compare_device_type(&in_devices, AUDIO_DEVICE_IN_WIRED_HEADSET)) {
                  snd_device = SND_DEVICE_IN_UNPROCESSED_HEADSET_MIC;
-         } else if (audio_is_usb_in_device(in_device | AUDIO_DEVICE_BIT_IN)) {
+         } else if (is_usb_in_device_type(&in_devices)) {
              snd_device = fixup_usb_headset_mic_snd_device(platform,
                                           SND_DEVICE_IN_UNPROCESSED_USB_HEADSET_MIC,
                                           SND_DEVICE_IN_UNPROCESSED_USB_HEADSET_MULTI_CHANNEL_MIC);
          }
     } else if ((source == AUDIO_SOURCE_VOICE_COMMUNICATION) ||
               (mode == AUDIO_MODE_IN_COMMUNICATION)) {
-        if (out_device & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_SPEAKER_SAFE) ||
-            out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
-            (out_device & (AUDIO_DEVICE_OUT_USB_DEVICE | AUDIO_DEVICE_OUT_USB_HEADSET) &&
+        if ((compare_device_type(out_devices, AUDIO_DEVICE_OUT_SPEAKER) ||
+             compare_device_type(out_devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) ||
+            compare_device_type(out_devices, AUDIO_DEVICE_OUT_WIRED_HEADPHONE) ||
+            ((compare_device_type(out_devices, AUDIO_DEVICE_OUT_USB_DEVICE) ||
+              compare_device_type(out_devices, AUDIO_DEVICE_OUT_USB_HEADSET)) &&
             !audio_extn_usb_is_capture_supported()))
-            in_device = AUDIO_DEVICE_IN_BACK_MIC;
-        else if (out_device & AUDIO_DEVICE_OUT_EARPIECE)
-            in_device = AUDIO_DEVICE_IN_BUILTIN_MIC;
-        else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET)
-            in_device = AUDIO_DEVICE_IN_WIRED_HEADSET;
-        else if (out_device & AUDIO_DEVICE_OUT_USB_DEVICE)
-            in_device = AUDIO_DEVICE_IN_USB_DEVICE;
+            reassign_device_list(&in_devices, AUDIO_DEVICE_IN_BACK_MIC, address);
+        else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_EARPIECE))
+            reassign_device_list(&in_devices, AUDIO_DEVICE_IN_BUILTIN_MIC, address);
+        else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_WIRED_HEADSET))
+            reassign_device_list(&in_devices, AUDIO_DEVICE_IN_WIRED_HEADSET, address);
+        else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_USB_DEVICE))
+            reassign_device_list(&in_devices, AUDIO_DEVICE_IN_USB_DEVICE, address);
 
-        in_device = ((out_device == AUDIO_DEVICE_NONE) ?
-                      AUDIO_DEVICE_IN_BUILTIN_MIC : in_device) & ~AUDIO_DEVICE_BIT_IN;
+        if (list_empty(out_devices))
+            reassign_device_list(&in_devices, (AUDIO_DEVICE_IN_BUILTIN_MIC & ~AUDIO_DEVICE_BIT_IN),
+                                 address);
 
         if (in)
-            snd_device = get_snd_device_for_voice_comm(my_data, in, out_device, in_device);
+            snd_device = get_snd_device_for_voice_comm(my_data, in, out_devices, &in_devices);
     } else if (source == AUDIO_SOURCE_MIC) {
-        if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC &&
+        if (compare_device_type(&in_devices, AUDIO_DEVICE_IN_BUILTIN_MIC) &&
                 channel_count == 1 ) {
             if(my_data->fluence_in_audio_rec) {
                if ((my_data->fluence_type & FLUENCE_QUAD_MIC) &&
                     (my_data->source_mic_type & SOURCE_QUAD_MIC)) {
                     snd_device = SND_DEVICE_IN_HANDSET_QMIC;
-                    platform_set_echo_reference(adev, true, out_device);
+                    platform_set_echo_reference(adev, true, out_devices);
                 } else if ((my_data->fluence_type & FLUENCE_QUAD_MIC) &&
                     (my_data->source_mic_type & SOURCE_THREE_MIC)) {
                     snd_device = SND_DEVICE_IN_HANDSET_TMIC_FLUENCE_PRO;
@@ -7012,11 +7013,11 @@
                 } else if ((my_data->fluence_type & FLUENCE_DUAL_MIC) &&
                     (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
                     snd_device = SND_DEVICE_IN_HANDSET_DMIC;
-                    platform_set_echo_reference(adev, true, out_device);
+                    platform_set_echo_reference(adev, true, out_devices);
                 }
             }
-        } else if (in_device & AUDIO_DEVICE_IN_LOOPBACK) {
-            if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+        } else if (compare_device_type(&in_devices, AUDIO_DEVICE_IN_LOOPBACK)) {
+            if (compare_device_type(&in_devices, AUDIO_DEVICE_IN_BUILTIN_MIC)) {
                 usecase = get_usecase_from_list(adev, uc_id);
                 if (usecase == NULL) {
                     ALOGE("%s: Could not find the record usecase", __func__);
@@ -7043,10 +7044,10 @@
         goto exit;
     }
 
-    if (in_device != AUDIO_DEVICE_NONE &&
-            !(in_device & AUDIO_DEVICE_IN_VOICE_CALL) &&
-            !(in_device & AUDIO_DEVICE_IN_COMMUNICATION)) {
-        if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+    if (!list_empty(&in_devices) &&
+            !(compare_device_type(&in_devices, AUDIO_DEVICE_IN_VOICE_CALL)) &&
+            !(compare_device_type(&in_devices, AUDIO_DEVICE_IN_COMMUNICATION))) {
+        if (compare_device_type(&in_devices, AUDIO_DEVICE_IN_BUILTIN_MIC)) {
             if ((in && (audio_extn_ssr_get_stream() == in)) ||
                 ((my_data->source_mic_type & SOURCE_QUAD_MIC) &&
                  channel_mask == AUDIO_CHANNEL_INDEX_MASK_4))
@@ -7060,7 +7061,7 @@
             else
                 snd_device = my_data->fluence_sb_enabled ? SND_DEVICE_IN_HANDSET_MIC_SB
                                  : SND_DEVICE_IN_HANDSET_MIC;
-        } else if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+        } else if (compare_device_type(&in_devices, AUDIO_DEVICE_IN_BACK_MIC)) {
             if ((my_data->source_mic_type & SOURCE_DUAL_MIC) &&
                     channel_count == 2)
                 snd_device = SND_DEVICE_IN_SPEAKER_DMIC_STEREO;
@@ -7068,11 +7069,11 @@
                 snd_device = my_data->fluence_sb_enabled ?
                                  SND_DEVICE_IN_SPEAKER_MIC_SB
                                  : SND_DEVICE_IN_SPEAKER_MIC;
-        } else if (in_device & AUDIO_DEVICE_IN_LINE) {
+        } else if (compare_device_type(&in_devices, AUDIO_DEVICE_IN_LINE)) {
             snd_device = SND_DEVICE_IN_LINE;
-        } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+        } else if (compare_device_type(&in_devices, AUDIO_DEVICE_IN_WIRED_HEADSET)) {
             snd_device = SND_DEVICE_IN_HEADSET_MIC;
-        } else if (in_device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+        } else if (compare_device_type(&in_devices, AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)) {
             if (adev->swb_speech_mode != SPEECH_MODE_INVALID) {
                 if (adev->bluetooth_nrec)
                     snd_device = SND_DEVICE_IN_BT_SCO_MIC_SWB_NREC;
@@ -7089,37 +7090,38 @@
                 else
                     snd_device = SND_DEVICE_IN_BT_SCO_MIC;
             }
-        } else if (in_device & AUDIO_DEVICE_IN_SPDIF) {
+        } else if (compare_device_type(&in_devices, AUDIO_DEVICE_IN_SPDIF)) {
             snd_device = SND_DEVICE_IN_SPDIF;
-        } else if (in_device & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
+        } else if (compare_device_type(&in_devices, AUDIO_DEVICE_IN_BLUETOOTH_A2DP)) {
             snd_device = SND_DEVICE_IN_BT_A2DP;
-        } else if (in_device & AUDIO_DEVICE_IN_AUX_DIGITAL) {
+        } else if (compare_device_type(&in_devices, AUDIO_DEVICE_IN_AUX_DIGITAL)) {
             snd_device = SND_DEVICE_IN_HDMI_MIC;
-        } else if (in_device & AUDIO_DEVICE_IN_HDMI_ARC) {
+        } else if (compare_device_type(&in_devices, AUDIO_DEVICE_IN_HDMI_ARC)) {
             snd_device = SND_DEVICE_IN_HDMI_ARC;
-        } else if (in_device & AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET ||
-                   in_device & AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET) {
+        } else if (compare_device_type(&in_devices, AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET) ||
+                   compare_device_type(&in_devices, AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET)) {
             snd_device = SND_DEVICE_IN_USB_HEADSET_MIC;
-        } else if (in_device & AUDIO_DEVICE_IN_FM_TUNER) {
+        } else if (compare_device_type(&in_devices, AUDIO_DEVICE_IN_FM_TUNER)) {
             snd_device = SND_DEVICE_IN_CAPTURE_FM;
-        } else if (audio_extn_usb_connected(NULL) && audio_is_usb_in_device(in_device | AUDIO_DEVICE_BIT_IN)) {
+        } else if (audio_extn_usb_connected(NULL) &&
+                   is_usb_in_device_type(&in_devices)) {
             snd_device = fixup_usb_headset_mic_snd_device(platform,
                                                   SND_DEVICE_IN_USB_HEADSET_MIC,
                                                   SND_DEVICE_IN_USB_HEADSET_MULTI_CHANNEL_MIC);
         } else {
-            ALOGE("%s: Unknown input device(s) %#x", __func__, in_device);
+            ALOGE("%s: Unknown input device(s) %#x", __func__, get_device_types(&in_devices));
             ALOGW("%s: Using default handset-mic", __func__);
             snd_device = my_data->fluence_sb_enabled ? SND_DEVICE_IN_HANDSET_MIC_SB
                              : SND_DEVICE_IN_HANDSET_MIC;
         }
     } else {
-        if (out_device & AUDIO_DEVICE_OUT_EARPIECE) {
+        if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_EARPIECE)) {
             snd_device = my_data->fluence_sb_enabled ? SND_DEVICE_IN_HANDSET_MIC_SB
                              : SND_DEVICE_IN_HANDSET_MIC;
-        } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+        } else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_WIRED_HEADSET)) {
             snd_device = SND_DEVICE_IN_HEADSET_MIC;
-        } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER ||
-                   out_device & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
+        } else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_SPEAKER) ||
+                   compare_device_type(out_devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
             if ((my_data->source_mic_type & SOURCE_DUAL_MIC) &&
                 (channel_count == 2)) {
                 snd_device = SND_DEVICE_IN_SPEAKER_DMIC_STEREO;
@@ -7136,11 +7138,11 @@
                                  SND_DEVICE_IN_SPEAKER_MIC_SB
                                  : SND_DEVICE_IN_SPEAKER_MIC;
             }
-        } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
-                        out_device & AUDIO_DEVICE_OUT_LINE) {
+        } else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_WIRED_HEADPHONE) ||
+                   compare_device_type(out_devices, AUDIO_DEVICE_OUT_LINE)) {
             snd_device = my_data->fluence_sb_enabled ? SND_DEVICE_IN_HANDSET_MIC_SB
                              : SND_DEVICE_IN_HANDSET_MIC;
-        } else if (out_device & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) {
+        } else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET)) {
             if (adev->swb_speech_mode != SPEECH_MODE_INVALID) {
                 if (adev->bluetooth_nrec)
                     snd_device = SND_DEVICE_IN_BT_SCO_MIC_SWB_NREC;
@@ -7157,14 +7159,13 @@
                 else
                     snd_device = SND_DEVICE_IN_BT_SCO_MIC;
             }
-        } else if (out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+        } else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
             snd_device = SND_DEVICE_IN_HDMI_MIC;
-        } else if (out_device & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET ||
-                   out_device & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
+        } else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET) ||
+                   compare_device_type(out_devices, AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET)) {
             snd_device = SND_DEVICE_IN_USB_HEADSET_MIC;
-        } else if (out_device &
-                    (AUDIO_DEVICE_OUT_USB_DEVICE |
-                     AUDIO_DEVICE_OUT_USB_HEADSET)) {
+        } else if (compare_device_type(out_devices, AUDIO_DEVICE_OUT_USB_DEVICE) ||
+                   compare_device_type(out_devices, AUDIO_DEVICE_OUT_USB_HEADSET)) {
             if (audio_extn_usb_is_capture_supported() && audio_extn_usb_connected(NULL))
                 snd_device = fixup_usb_headset_mic_snd_device(platform,
                                                       SND_DEVICE_IN_USB_HEADSET_MIC,
@@ -7173,7 +7174,7 @@
               snd_device = SND_DEVICE_IN_HANDSET_MIC;
 
         } else {
-            ALOGE("%s: Unknown output device(s) %#x", __func__, out_device);
+            ALOGE("%s: Unknown output device(s) %#x", __func__, get_device_types(out_devices));
             ALOGW("%s: Using default handset-mic", __func__);
             snd_device = my_data->fluence_sb_enabled ? SND_DEVICE_IN_HANDSET_MIC_SB
                              : SND_DEVICE_IN_HANDSET_MIC;
@@ -7606,6 +7607,7 @@
     uint8_t *dptr = NULL;
     int32_t dlen;
     int err, ret;
+    char *address = "";
     if(value == NULL || platform == NULL || parms == NULL) {
         ALOGE("[%s] received null pointer, failed",__func__);
         goto done_key_audcal;
@@ -7635,13 +7637,17 @@
             goto done_key_audcal;
         }
 
+        list_init(&out.device_list);
         if (cal.dev_id) {
           if (audio_is_input_device(cal.dev_id)) {
               // FIXME: why pass an input device whereas
               // platform_get_input_snd_device() expects as an output device?
-              cal.snd_dev_id = platform_get_input_snd_device(platform, NULL, cal.dev_id);
+              struct listnode cal_devices;
+              list_init(&cal_devices);
+              update_device_list(&cal_devices, cal.dev_id, address, true);
+              cal.snd_dev_id = platform_get_input_snd_device(platform, NULL, &cal_devices);
           } else {
-              out.devices = cal.dev_id;
+              reassign_device_list(&out.device_list, cal.dev_id, address);
               out.sample_rate = cal.sampling_rate;
               cal.snd_dev_id = platform_get_output_snd_device(platform, &out);
           }
@@ -8198,6 +8204,7 @@
     char *rparms=NULL;
     int ret=0, err;
     uint32_t param_len;
+    char *address = "";
 
     if(query==NULL || platform==NULL || reply==NULL) {
         ALOGE("[%s] received null pointer",__func__);
@@ -8219,10 +8226,14 @@
         goto done;
     }
 
+    list_init(&out.device_list);
     if (cal.dev_id & AUDIO_DEVICE_BIT_IN) {
-        cal.snd_dev_id = platform_get_input_snd_device(platform, NULL, cal.dev_id);
-    } else if(cal.dev_id) {
-        out.devices = cal.dev_id;
+        struct listnode devices;
+        list_init(&devices);
+        update_device_list(&devices, cal.dev_id, address, true);
+        cal.snd_dev_id = platform_get_input_snd_device(platform, NULL, &devices);
+    } else if (cal.dev_id) {
+        reassign_device_list(&out.device_list, cal.dev_id, address);
         out.sample_rate = cal.sampling_rate;
         cal.snd_dev_id = platform_get_output_snd_device(platform, &out);
     }
@@ -9042,6 +9053,7 @@
     bool passthrough_enabled = false;
     int controller = -1;
     int stream = -1;
+    uint32_t compr_passthr = 0;
 
     if (!usecase) {
         ALOGE("%s: becf: HDMI: usecase is NULL", __func__);
@@ -9067,8 +9079,15 @@
           ", usecase = %d", __func__, bit_width,
           sample_rate, channels, usecase->id);
 
+#ifdef AUDIO_GKI_ENABLED
+    /* out->compr_config.codec->reserved[0] is for compr_passthr */
+    compr_passthr = usecase->stream.out->compr_config.codec->reserved[0];
+#else
+    compr_passthr = usecase->stream.out->compr_config.codec->compr_passthr;
+#endif
+
     if (audio_extn_passthru_is_enabled() && audio_extn_passthru_is_active()
-        && (usecase->stream.out->compr_config.codec->compr_passthr != 0)) {
+        && (compr_passthr != 0)) {
         passthrough_enabled = true;
         ALOGI("passthrough is enabled for this stream");
     }
@@ -9109,7 +9128,7 @@
         if (((usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
             (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC) ||
             (usecase->stream.out->format == AUDIO_FORMAT_DOLBY_TRUEHD))
-            && (usecase->stream.out->compr_config.codec->compr_passthr == PASSTHROUGH)) {
+            && (compr_passthr == PASSTHROUGH)) {
             sample_rate = sample_rate * 4;
             if (sample_rate > HDMI_PASSTHROUGH_MAX_SAMPLE_RATE)
                 sample_rate = HDMI_PASSTHROUGH_MAX_SAMPLE_RATE;
@@ -9241,7 +9260,7 @@
     }
 
     /* Native playback is preferred for Headphone/HS device over 192Khz */
-    if (!voice_call_active && codec_device_supports_native_playback(usecase->devices)) {
+    if (!voice_call_active && codec_device_supports_native_playback(&usecase->device_list)) {
         if (audio_is_true_native_stream_active(adev)) {
             if (check_hdset_combo_device(snd_device)) {
                 /*
@@ -9370,7 +9389,7 @@
      * Handset and speaker may have diffrent backend. Check if the device is speaker or handset,
      * and these devices are restricited to 48kHz.
      */
-    if (!codec_device_supports_native_playback(usecase->devices) &&
+    if (!codec_device_supports_native_playback(&usecase->device_list) &&
         (platform_check_backends_match(SND_DEVICE_OUT_SPEAKER, snd_device) ||
          platform_check_backends_match(SND_DEVICE_OUT_HANDSET, snd_device))) {
         int bw = platform_get_snd_device_bit_width(SND_DEVICE_OUT_SPEAKER);
@@ -9706,7 +9725,8 @@
         backend_cfg.bit_width= usecase->stream.in->bit_width;
         backend_cfg.format= usecase->stream.in->format;
         backend_cfg.channels = audio_channel_count_from_in_mask(usecase->stream.in->channel_mask);
-        if (is_loopback_input_device(usecase->stream.in->device)) {
+        if (is_loopback_input_device(
+                    get_device_types(&usecase->stream.in->device_list))) {
             int bw = platform_get_snd_device_bit_width(snd_device);
             if ((-ENOSYS != bw) && (backend_cfg.bit_width > (uint32_t)bw)) {
                 backend_cfg.bit_width = bw;
@@ -11386,7 +11406,8 @@
     list_for_each(node, &adev->usecase_list) {
         usecase = node_to_item(node, struct audio_usecase, list);
         if (usecase->stream.out && usecase->type == PCM_PLAYBACK &&
-                usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
+            compare_device_type(&usecase->stream.out->device_list,
+                                AUDIO_DEVICE_OUT_SPEAKER)) {
             /*
              * If acdb tuning is different for SPEAKER_REVERSE, it is must
              * to perform device switch to disable the current backend to
@@ -11633,9 +11654,11 @@
     }
     size_t max_mic_count = my_data->declared_mic_count;
     size_t actual_mic_count = 0;
+    struct listnode devices;
+    list_init(&devices);
 
     snd_device_t active_input_snd_device =
-            platform_get_input_snd_device(platform, usecase->stream.in, AUDIO_DEVICE_NONE);
+            platform_get_input_snd_device(platform, usecase->stream.in, &devices);
     if (active_input_snd_device == SND_DEVICE_NONE) {
         ALOGI("%s: No active microphones found", __func__);
         goto end;
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index f59f514..7bb699c 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -50,28 +50,6 @@
     SPKR_2
 };
 
-/*
- * Below are the devices for which is back end is same, SLIMBUS_0_RX.
- * All these devices are handled by the internal HW codec. We can
- * enable any one of these devices at any time. An exception here is
- * 44.1k headphone which uses different backend. This is filtered
- * as different hal internal device in the code but remains same
- * as standard android device AUDIO_DEVICE_OUT_WIRED_HEADPHONE
- * for other layers.
- */
-#define AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND \
-    (AUDIO_DEVICE_OUT_EARPIECE | AUDIO_DEVICE_OUT_SPEAKER | \
-     AUDIO_DEVICE_OUT_SPEAKER_SAFE | \
-     AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE | \
-     AUDIO_DEVICE_OUT_LINE)
-
-/*
- * Below are the input devices for which back end is same, SLIMBUS_0_TX.
- * All these devices are handled by the internal HW codec. We can
- * enable any one of these devices at any time
- */
-int AUDIO_DEVICE_IN_ALL_CODEC_BACKEND;
-
 /* Sound devices specific to the platform
  * The DEVICE_OUT_* and DEVICE_IN_* should be mapped to these sound
  * devices to enable corresponding mixer paths
diff --git a/hal/platform_api.h b/hal/platform_api.h
index cd5f888..fbf159a 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -207,7 +207,7 @@
 snd_device_t platform_get_output_snd_device(void *platform, struct stream_out *out);
 snd_device_t platform_get_input_snd_device(void *platform,
                                            struct stream_in *in,
-                                           audio_devices_t out_device);
+                                           struct listnode *out_devices);
 int platform_set_hdmi_channels(void *platform, int channel_count);
 int platform_edid_get_max_channels(void *platform);
 void platform_add_operator_specific_device(snd_device_t snd_device,
@@ -268,7 +268,8 @@
                    struct audio_usecase *usecase, snd_device_t snd_device);
 int platform_get_usecase_index(const char * usecase);
 int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t pcm_id);
-void platform_set_echo_reference(struct audio_device *adev, bool enable, audio_devices_t out_device);
+void platform_set_echo_reference(struct audio_device *adev, bool enable,
+                                 struct listnode *out_devices);
 int platform_check_and_set_swap_lr_channels(struct audio_device *adev, bool swap_channels);
 int platform_set_swap_channels(struct audio_device *adev, bool swap_channels);
 void platform_get_device_to_be_id_map(int **be_id_map, int *length);
diff --git a/hal/voice.c b/hal/voice.c
index 0000d72..818eb94 100644
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -239,11 +239,12 @@
     uc_info->id = usecase_id;
     uc_info->type = VOICE_CALL;
     uc_info->stream.out = adev->current_call_output;
-    uc_info->devices = adev->current_call_output->devices;
+    list_init(&uc_info->device_list);
+    assign_devices(&uc_info->device_list, &adev->current_call_output->device_list);
 
-    if (popcount(uc_info->devices) == 2) {
+    if (list_length(&uc_info->device_list) == 2) {
         ALOGE("%s: Invalid combo device(%#x) for voice call", __func__,
-              uc_info->devices);
+              get_device_types(&uc_info->device_list));
         ret = -EIO;
         goto error_start_voice;
     }
@@ -252,7 +253,7 @@
     uc_info->out_snd_device = SND_DEVICE_NONE;
     adev->voice.use_device_mute = false;
 
-    if (audio_is_bluetooth_sco_device(uc_info->devices) && !adev->bt_sco_on) {
+    if (is_sco_out_device_type(&uc_info->device_list) && !adev->bt_sco_on) {
         ALOGE("start_call: couldn't find BT SCO, SCO is not ready");
         adev->voice.in_call = false;
         ret = -EIO;
diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c
index fbd6d6f..2d14bf0 100644
--- a/hal/voice_extn/compress_voip.c
+++ b/hal/voice_extn/compress_voip.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2017, 2020, The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -450,7 +450,7 @@
         goto error;
     }
 
-    if (out->devices & AUDIO_DEVICE_OUT_ALL_SCO) {
+    if (is_sco_out_device_type(&out->device_list)) {
          if (!adev->bt_sco_on) {
              ALOGE("%s: SCO profile is not ready, return error", __func__);
              ret = -EAGAIN;
@@ -466,7 +466,7 @@
     uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
     if (uc_info) {
         uc_info->stream.out = out;
-        uc_info->devices = out->devices;
+        assign_devices(&uc_info->device_list, &out->device_list);
     } else {
         ret = -EINVAL;
         ALOGE("%s: exit(%d): failed to get use case info", __func__, ret);
@@ -492,7 +492,7 @@
         goto error;
     }
 
-    if (audio_is_bluetooth_sco_device(in->device) && !adev->bt_sco_on) {
+    if (is_sco_in_device_type(&in->device_list) && !adev->bt_sco_on) {
         ret = -EIO;
         ALOGE("%s SCO is not ready return error %d", __func__,ret);
         goto error;
diff --git a/visualizer/offload_visualizer.c b/visualizer/offload_visualizer.c
index 442ef3e..e1a34a0 100644
--- a/visualizer/offload_visualizer.c
+++ b/visualizer/offload_visualizer.c
@@ -971,17 +971,19 @@
 
         if (context->state == EFFECT_STATE_ACTIVE) {
             int32_t latency_ms = visu_ctxt->latency;
-            const uint32_t delta_ms = visualizer_get_delta_time_ms_from_updated_time(visu_ctxt);
+            const int32_t delta_ms = visualizer_get_delta_time_ms_from_updated_time(visu_ctxt);
             latency_ms -= delta_ms;
             if (latency_ms < 0) {
                 latency_ms = 0;
             }
             const uint32_t delta_smp = context->config.inputCfg.samplingRate * latency_ms / 1000;
 
-            int32_t capture_point = visu_ctxt->capture_idx - visu_ctxt->capture_size - delta_smp;
-            int32_t capture_size = visu_ctxt->capture_size;
+            int64_t capture_point = visu_ctxt->capture_idx;
+            capture_point -= visu_ctxt->capture_size;
+            capture_point -= delta_smp;
+            int64_t capture_size = visu_ctxt->capture_size;
             if (capture_point < 0) {
-                int32_t size = -capture_point;
+                int64_t size = -capture_point;
                 if (size > capture_size)
                     size = capture_size;