Merge "configs: Quad mic configuration from application picks up invalid          (single mic) topology due to addition of fast input profile.          Add dedicated profile for quad mic use case to make sure HAL          selects proper topology (quad mic)."
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/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/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..b873874 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;
@@ -1182,6 +1182,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 +1197,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 +1251,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 +1302,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 +1313,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 +1606,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 +1646,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 +1728,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 +1815,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 +1836,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 +1849,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 +1871,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 +2347,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 +2360,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 +2584,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 +2594,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 +2631,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 +2654,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 +2665,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 +2675,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 +2698,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 +2713,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 +2735,7 @@
 
                 in_snd_device = platform_get_input_snd_device(adev->platform,
                                                               priority_in,
-                                                              out_device);
+                                                              &out_devices);
             }
         }
     }
@@ -2729,9 +2747,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 +2870,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 +3000,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 +3044,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 +3083,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 +3194,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 +3575,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 +3592,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 +3617,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 +3694,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 +3718,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 +3731,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 +3773,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 +3792,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 +3800,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 +3979,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 +4419,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 +4630,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 +4655,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 +4668,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 +4681,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 +4702,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 +4710,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 +4747,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 +4784,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 +4800,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 +4818,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 +4879,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 +5209,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 +5383,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 +5577,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 +5608,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 +5645,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 +5662,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 +5703,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 +6062,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 +6101,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 +6629,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 +6655,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 +6681,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 +6713,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 +7389,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 +7489,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 +7598,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 +7734,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 +7791,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 +7937,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 +7996,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 +8127,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 +8169,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 +8457,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 +8607,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 +8628,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 +8964,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 +9050,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 +9211,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 +9339,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 +9406,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 +9422,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 +9567,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 +9666,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 +9695,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,17 +9719,13 @@
         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:
@@ -9718,10 +9788,9 @@
     // 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);
+            ret = route_input_stream((struct stream_in *) stream, &devices, input_source);
     }
 
     if (ret < 0) {
@@ -9763,7 +9832,6 @@
 {
     struct audio_device *adev = (struct audio_device *) dev;
     int ret = 0;
-    char *addr = "";
     audio_source_t input_source = AUDIO_SOURCE_DEFAULT;
 
     if (handle == AUDIO_PATCH_HANDLE_NONE) {
@@ -9816,11 +9884,12 @@
 
     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)
@@ -9982,7 +10051,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 +10065,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 +10083,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 +10094,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;
             }
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 5604977..5db02f1 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;
@@ -550,7 +551,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 +799,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;