diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c
index 452a1c4..b74a3e7 100644
--- a/src/modules/alsa/alsa-ucm.c
+++ b/src/modules/alsa/alsa-ucm.c
@@ -1013,6 +1013,18 @@ static int ucm_create_profile(pa_alsa_ucm_config *ucm, pa_alsa_profile_set *ps,
     return 0;
 }
 
+static pa_alsa_ucm_device *find_ucm_dev(pa_alsa_ucm_verb *verb, const char *dev_name) {
+    pa_alsa_ucm_device *dev;
+
+    PA_LLIST_FOREACH(dev, verb->devices) {
+        const char *name = pa_proplist_gets(dev->proplist, PA_PROP_UCM_NAME);
+        if (pa_streq(name, dev_name))
+            return dev;
+    }
+
+    return NULL;
+}
+
 pa_alsa_profile_set* pa_ucm_add_profile_set(pa_alsa_ucm_config *ucm, pa_channel_map *default_channel_map) {
     pa_alsa_ucm_verb *verb;
     pa_alsa_profile_set *ps;
@@ -1081,3 +1093,86 @@ void pa_ucm_free(pa_alsa_ucm_config *ucm) {
         ucm->ucm_mgr = NULL;
     }
 }
+
+static pa_bool_t stream_routed_to_mod_intent (pa_alsa_ucm_verb *verb,
+        pa_alsa_ucm_modifier *mod, const char *mapping_name) {
+    int i;
+    const char *dev_name;
+    pa_alsa_ucm_device *dev;
+    pa_alsa_mapping *mapping;
+
+    /* check if mapping_name is same as one of the modifier's supported device */
+    for (i=0; i<mod->n_suppdev; i++) {
+        dev_name = mod->supported_devices[i];
+        /* first find the supported device */
+        dev = find_ucm_dev(verb, dev_name);
+        if (dev) {
+            /* then match the mapping name */
+            mapping = mod->action_direct == PA_ALSA_UCM_DIRECT_SINK ? dev->playback_mapping : dev->capture_mapping;
+            if (mapping && pa_streq(mapping->name, mapping_name))
+                return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+/* enable the modifier when both of the conditions are met
+ * 1. the first stream with matched role starts
+ * 2. the stream is routed to the device of the modifier specifies.
+ */
+void pa_ucm_roled_stream_begin(pa_alsa_ucm_config *ucm,
+        const char *role, const char *mapping_name, int is_sink) {
+    pa_alsa_ucm_modifier *mod;
+
+    if (!ucm->active_verb)
+        return;
+
+    PA_LLIST_FOREACH(mod, ucm->active_verb->modifiers) {
+        if (((mod->action_direct == PA_ALSA_UCM_DIRECT_SINK && is_sink) ||
+            (mod->action_direct == PA_ALSA_UCM_DIRECT_SOURCE && !is_sink)) &&
+            (!strcasecmp(mod->media_role, role))) {
+            if (stream_routed_to_mod_intent(ucm->active_verb, mod, mapping_name)) {
+                if (mod->enabled_counter == 0) {
+                    const char *mod_name = pa_proplist_gets(mod->proplist, PA_PROP_UCM_NAME);
+                    pa_log_info("Enable ucm modifiers %s", mod_name);
+                    if (snd_use_case_set(ucm->ucm_mgr, "_enamod", mod_name) < 0)
+                        pa_log("failed to enable ucm modifier %s", mod_name);
+                }
+                mod->enabled_counter++;
+                /* TODO: set port of the sink/source to modifier's intent device? */
+            }
+            break;
+        }
+    }
+}
+
+/* disable the modifier when both of the conditions are met
+ * 1. the last stream with matched role ends
+ * 2. the stream is routed to the device of the modifier specifies.
+ */
+void pa_ucm_roled_stream_end(pa_alsa_ucm_config *ucm,
+        const char *role, const char *mapping_name, int is_sink) {
+    pa_alsa_ucm_modifier *mod;
+
+    if (!ucm->active_verb)
+        return;
+
+    PA_LLIST_FOREACH(mod, ucm->active_verb->modifiers) {
+        if (((mod->action_direct == PA_ALSA_UCM_DIRECT_SINK && is_sink) ||
+            (mod->action_direct == PA_ALSA_UCM_DIRECT_SOURCE && !is_sink)) &&
+            (!strcasecmp(mod->media_role, role))) {
+            if (stream_routed_to_mod_intent(ucm->active_verb, mod, mapping_name)) {
+                mod->enabled_counter--;
+                if (mod->enabled_counter == 0) {
+                    const char *mod_name = pa_proplist_gets(mod->proplist, PA_PROP_UCM_NAME);
+                    pa_log_info("Disable ucm modifiers %s", mod_name);
+                    if (snd_use_case_set(ucm->ucm_mgr, "_dismod", mod_name) < 0)
+                        pa_log("failed to disable ucm modifier %s", mod_name);
+                }
+                /* TODO: set port of the sink/source to modifier's intent device? */
+            }
+            break;
+        }
+    }
+}
diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h
index 18b6fe0..8e2dd71 100644
--- a/src/modules/alsa/alsa-ucm.h
+++ b/src/modules/alsa/alsa-ucm.h
@@ -49,6 +49,9 @@ int pa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *port,
 
 void pa_ucm_free(pa_alsa_ucm_config *ucm);
 
+void pa_ucm_roled_stream_begin(pa_alsa_ucm_config *ucm, const char *role, const char *mapping_name, int is_sink);
+void pa_ucm_roled_stream_end(pa_alsa_ucm_config *ucm, const char *role, const char *mapping_name, int is_sink);
+
 /* UCM modifier action direction */
 enum {
     PA_ALSA_UCM_DIRECT_NONE = 0,
@@ -82,6 +85,9 @@ struct pa_alsa_ucm_modifier {
     const char **supported_devices;
     int action_direct;
     char *media_role;
+
+    /* runtime variable */
+    int enabled_counter;
 };
 
 struct pa_alsa_ucm_verb {
diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
index 7d09938..4802a39 100644
--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -124,6 +124,18 @@ struct userdata {
     /* ucm stuffs */
     pa_bool_t use_ucm;
     pa_alsa_ucm_config ucm;
+
+    /* hooks for modifier action */
+    pa_hook_slot
+        *sink_input_put_hook_slot,
+        *source_output_put_hook_slot,
+        *sink_input_unlink_hook_slot,
+        *source_output_unlink_hook_slot,
+
+        *sink_input_move_start_hook_slot,
+        *source_output_move_start_hook_slot,
+        *sink_input_move_finish_hook_slot,
+        *source_output_move_finish_hook_slot;
 };
 
 struct profile_data {
@@ -286,7 +298,7 @@ static void init_profile(struct userdata *u) {
     uint32_t idx;
     pa_alsa_mapping *am;
     struct profile_data *d;
-    struct pa_alsa_ucm_config *ucm = &u->ucm;
+    pa_alsa_ucm_config *ucm = &u->ucm;
 
     pa_assert(u);
 
@@ -476,7 +488,7 @@ static int card_query_ucm_profiles(struct userdata *u, int card_index)
 
     /* get the properties of each UCM verb */
     for (i = 0; i < num_verbs; i += 2) {
-        struct pa_alsa_ucm_verb *verb;
+        pa_alsa_ucm_verb *verb;
 
         /* Get devices and modifiers for each verb */
         err = pa_ucm_get_verb(u->ucm.ucm_mgr, verb_list[i], verb_list[i+1], &verb);
@@ -512,6 +524,102 @@ name_fail:
     return err;
 }
 
+static pa_hook_result_t sink_input_put_hook_callback(
+        pa_core *c, pa_sink_input *sink_input, struct userdata *u) {
+    const char *role;
+    const char *mapping_name;
+    pa_sink *sink = sink_input->sink;
+
+    pa_assert(sink);
+
+    role = pa_proplist_gets(sink_input->proplist, PA_PROP_MEDIA_ROLE);
+    mapping_name = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_PROFILE_NAME);
+
+    /* new sink input linked to sink of this card */
+    if (role && sink->card == u->card)
+        pa_ucm_roled_stream_begin(&u->ucm, role, mapping_name, 1);
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t source_output_put_hook_callback(
+        pa_core *c, pa_source_output *source_output, struct userdata *u) {
+    const char *role;
+    const char *mapping_name;
+    pa_source *source = source_output->source;
+
+    pa_assert(source);
+
+    role = pa_proplist_gets(source_output->proplist, PA_PROP_MEDIA_ROLE);
+    mapping_name = pa_proplist_gets(source->proplist, PA_PROP_DEVICE_PROFILE_NAME);
+
+    /* new source output linked to source of this card */
+    if (role && source->card == u->card)
+        pa_ucm_roled_stream_begin(&u->ucm, role, mapping_name, 0);
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t sink_input_unlink_hook_callback(
+        pa_core *c, pa_sink_input *sink_input, struct userdata *u) {
+    const char *role;
+    const char *mapping_name;
+    pa_sink *sink = sink_input->sink;
+
+    pa_assert(sink);
+
+    role = pa_proplist_gets(sink_input->proplist, PA_PROP_MEDIA_ROLE);
+    mapping_name = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_PROFILE_NAME);
+
+    /* new sink input unlinked from sink of this card */
+    if (role && sink->card == u->card)
+        pa_ucm_roled_stream_end(&u->ucm, role, mapping_name, 1);
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t source_output_unlink_hook_callback(
+        pa_core *c, pa_source_output *source_output, struct userdata *u) {
+    const char *role;
+    const char *mapping_name;
+    pa_source *source = source_output->source;
+
+    pa_assert(source);
+
+    role = pa_proplist_gets(source_output->proplist, PA_PROP_MEDIA_ROLE);
+    mapping_name = pa_proplist_gets(source->proplist, PA_PROP_DEVICE_PROFILE_NAME);
+
+    /* new source output unlinked from source of this card */
+    if (role && source->card == u->card)
+        pa_ucm_roled_stream_end(&u->ucm, role, mapping_name, 0);
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t sink_input_move_start_hook_callback(
+        pa_core *c, pa_sink_input *sink_input, struct userdata *u) {
+    /* same as sink input unlink */
+    return sink_input_unlink_hook_callback(c, sink_input, u);
+}
+
+static pa_hook_result_t source_output_move_start_hook_callback(
+        pa_core *c, pa_source_output *source_output, struct userdata *u) {
+    /* same as source output unlink */
+    return source_output_unlink_hook_callback(c, source_output, u);
+}
+
+static pa_hook_result_t sink_input_move_finish_hook_callback(
+        pa_core *c, pa_sink_input *sink_input, struct userdata *u) {
+    /* same as sink input put */
+    return sink_input_put_hook_callback(c, sink_input, u);
+}
+
+static pa_hook_result_t source_output_move_finish_hook_callback(
+        pa_core *c, pa_source_output *source_output, struct userdata *u) {
+    /* same as source output put */
+    return source_output_put_hook_callback(c, source_output, u);
+}
+
 int pa__init(pa_module *m) {
     pa_card_new_data data;
     pa_modargs *ma;
@@ -563,6 +671,38 @@ int pa__init(pa_module *m) {
     pa_modargs_get_value_boolean(ma, "use_ucm", &u->use_ucm);
     if (u->use_ucm && !card_query_ucm_profiles(u, u->alsa_card_index)) {
         pa_log_info("Found UCM profiles");
+
+        /* hook start of sink input/source output to enable modifiers */
+        /* A little bit later than module-role-cork */
+        u->sink_input_put_hook_slot = pa_hook_connect(
+                &m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_LATE+10,
+                (pa_hook_cb_t) sink_input_put_hook_callback, u);
+        u->source_output_put_hook_slot = pa_hook_connect(
+                &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], PA_HOOK_LATE+10,
+                (pa_hook_cb_t) source_output_put_hook_callback, u);
+
+        /* hook end of sink input/source output to disable modifiers */
+        /* A little bit later than module-role-cork */
+        u->sink_input_unlink_hook_slot = pa_hook_connect(
+                &m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK],
+                PA_HOOK_LATE+10, (pa_hook_cb_t) sink_input_unlink_hook_callback, u);
+        u->source_output_unlink_hook_slot = pa_hook_connect(
+                &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK],
+                PA_HOOK_LATE+10, (pa_hook_cb_t) source_output_unlink_hook_callback, u);
+
+        /* hook move start of sink input/source output to disable modifiers */
+        /* A little bit later than module-role-cork */
+        u->sink_input_move_start_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_START],
+                PA_HOOK_LATE+10, (pa_hook_cb_t) sink_input_move_start_hook_callback, u);
+        u->source_output_move_start_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_START],
+                PA_HOOK_LATE+10, (pa_hook_cb_t) source_output_move_start_hook_callback, u);
+
+        /* hook move finish of sink input/source output to enable modifiers */
+        /* A little bit later than module-role-cork */
+        u->sink_input_move_finish_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FINISH],
+                PA_HOOK_LATE+10, (pa_hook_cb_t) sink_input_move_finish_hook_callback, u);
+        u->source_output_move_finish_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FINISH],
+                PA_HOOK_LATE+10, (pa_hook_cb_t) source_output_move_finish_hook_callback, u);
     }
     else {
         u->use_ucm = FALSE;
@@ -695,6 +835,30 @@ void pa__done(pa_module*m) {
     if (!(u = m->userdata))
         goto finish;
 
+    if (u->sink_input_put_hook_slot)
+        pa_hook_slot_free(u->sink_input_put_hook_slot);
+
+    if (u->sink_input_unlink_hook_slot)
+        pa_hook_slot_free(u->sink_input_unlink_hook_slot);
+
+    if (u->source_output_put_hook_slot)
+        pa_hook_slot_free(u->source_output_put_hook_slot);
+
+    if (u->source_output_unlink_hook_slot)
+        pa_hook_slot_free(u->source_output_unlink_hook_slot);
+
+    if (u->sink_input_move_start_hook_slot)
+        pa_hook_slot_free(u->sink_input_move_start_hook_slot);
+
+    if (u->source_output_move_start_hook_slot)
+        pa_hook_slot_free(u->source_output_move_start_hook_slot);
+
+    if (u->sink_input_move_finish_hook_slot)
+        pa_hook_slot_free(u->sink_input_move_finish_hook_slot);
+
+    if (u->source_output_move_finish_hook_slot)
+        pa_hook_slot_free(u->source_output_move_finish_hook_slot);
+
     if (u->mixer_fdl)
         pa_alsa_fdlist_free(u->mixer_fdl);
     if (u->mixer_handle)
