bool init_attr,
            const char *name, const char *metric_id, struct perf_pmu *pmu,
            struct list_head *config_terms, bool auto_merge_stats,
-           struct perf_cpu_map *cpu_list)
+           struct perf_cpu_map *cpu_list, u64 alternate_hw_config)
 {
        struct evsel *evsel;
        struct perf_cpu_map *cpus = perf_cpu_map__is_empty(cpu_list) && pmu ? pmu->cpus : cpu_list;
        evsel->auto_merge_stats = auto_merge_stats;
        evsel->pmu = pmu;
        evsel->pmu_name = pmu ? strdup(pmu->name) : NULL;
+       evsel->alternate_hw_config = alternate_hw_config;
 
        if (name)
                evsel->name = strdup(name);
 {
        return __add_event(/*list=*/NULL, &idx, attr, /*init_attr=*/false, name,
                           metric_id, pmu, /*config_terms=*/NULL,
-                          /*auto_merge_stats=*/false, /*cpu_list=*/NULL);
+                          /*auto_merge_stats=*/false, /*cpu_list=*/NULL,
+                          /*alternate_hw_config=*/PERF_COUNT_HW_MAX);
 }
 
 static int add_event(struct list_head *list, int *idx,
                     struct perf_event_attr *attr, const char *name,
-                    const char *metric_id, struct list_head *config_terms)
+                    const char *metric_id, struct list_head *config_terms,
+                    u64 alternate_hw_config)
 {
        return __add_event(list, idx, attr, /*init_attr*/true, name, metric_id,
                           /*pmu=*/NULL, config_terms,
-                          /*auto_merge_stats=*/false, /*cpu_list=*/NULL) ? 0 : -ENOMEM;
+                          /*auto_merge_stats=*/false, /*cpu_list=*/NULL,
+                          alternate_hw_config) ? 0 : -ENOMEM;
 }
 
 static int add_event_tool(struct list_head *list, int *idx,
        evsel = __add_event(list, idx, &attr, /*init_attr=*/true, /*name=*/NULL,
                            /*metric_id=*/NULL, /*pmu=*/NULL,
                            /*config_terms=*/NULL, /*auto_merge_stats=*/false,
-                           cpu_list);
+                           cpu_list,
+                           /*alternate_hw_config=*/PERF_COUNT_HW_MAX);
        perf_cpu_map__put(cpu_list);
        if (!evsel)
                return -ENOMEM;
 static int parse_events_add_pmu(struct parse_events_state *parse_state,
                                struct list_head *list, struct perf_pmu *pmu,
                                const struct parse_events_terms *const_parsed_terms,
-                               bool auto_merge_stats);
+                               bool auto_merge_stats, u64 alternate_hw_config);
 
 int parse_events_add_cache(struct list_head *list, int *idx, const char *name,
                           struct parse_events_state *parse_state,
                         */
                        ret = parse_events_add_pmu(parse_state, list, pmu,
                                                   parsed_terms,
-                                                  perf_pmu__auto_merge_stats(pmu));
+                                                  perf_pmu__auto_merge_stats(pmu),
+                                                  /*alternate_hw_config=*/PERF_COUNT_HW_MAX);
                        if (ret)
                                return ret;
                        continue;
 
                if (__add_event(list, idx, &attr, /*init_attr*/true, config_name ?: name,
                                metric_id, pmu, &config_terms, /*auto_merge_stats=*/false,
-                               /*cpu_list=*/NULL) == NULL)
+                               /*cpu_list=*/NULL,
+                               /*alternate_hw_config=*/PERF_COUNT_HW_MAX) == NULL)
                        return -ENOMEM;
 
                free_config_terms(&config_terms);
        name = get_config_name(head_config);
 
        return add_event(list, &parse_state->idx, &attr, name, /*mertic_id=*/NULL,
-                        &config_terms);
+                       &config_terms, /*alternate_hw_config=*/PERF_COUNT_HW_MAX);
 }
 
 static int check_type_val(struct parse_events_term *term,
                if (perf_pmu__have_event(pmu, term->config)) {
                        term->type_term = PARSE_EVENTS__TERM_TYPE_USER;
                        term->no_value = true;
+                       term->alternate_hw_config = true;
                } else {
                        attr->type = PERF_TYPE_HARDWARE;
                        attr->config = term->val.num;
        name = get_config_name(head_config);
        metric_id = get_config_metric_id(head_config);
        ret = __add_event(list, &parse_state->idx, &attr, /*init_attr*/true, name,
-                       metric_id, pmu, &config_terms, /*auto_merge_stats=*/false,
-                       /*cpu_list=*/NULL) ? 0 : -ENOMEM;
+                         metric_id, pmu, &config_terms, /*auto_merge_stats=*/false,
+                         /*cpu_list=*/NULL, /*alternate_hw_config=*/PERF_COUNT_HW_MAX
+               ) == NULL ? -ENOMEM : 0;
        free_config_terms(&config_terms);
        return ret;
 }
 static int parse_events_add_pmu(struct parse_events_state *parse_state,
                                struct list_head *list, struct perf_pmu *pmu,
                                const struct parse_events_terms *const_parsed_terms,
-                               bool auto_merge_stats)
+                               bool auto_merge_stats, u64 alternate_hw_config)
 {
        struct perf_event_attr attr;
        struct perf_pmu_info info;
                                    /*init_attr=*/true, /*name=*/NULL,
                                    /*metric_id=*/NULL, pmu,
                                    /*config_terms=*/NULL, auto_merge_stats,
-                                   /*cpu_list=*/NULL);
+                                   /*cpu_list=*/NULL, alternate_hw_config);
                return evsel ? 0 : -ENOMEM;
        }
 
 
        /* Look for event names in the terms and rewrite into format based terms. */
        if (perf_pmu__check_alias(pmu, &parsed_terms,
-                                 &info, &alias_rewrote_terms, err)) {
+                                 &info, &alias_rewrote_terms,
+                                 &alternate_hw_config, err)) {
                parse_events_terms__exit(&parsed_terms);
                return -EINVAL;
        }
        evsel = __add_event(list, &parse_state->idx, &attr, /*init_attr=*/true,
                            get_config_name(&parsed_terms),
                            get_config_metric_id(&parsed_terms), pmu,
-                           &config_terms, auto_merge_stats, /*cpu_list=*/NULL);
+                           &config_terms, auto_merge_stats, /*cpu_list=*/NULL,
+                           alternate_hw_config);
        if (!evsel) {
                parse_events_terms__exit(&parsed_terms);
                return -ENOMEM;
 }
 
 int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
-                              const char *event_name,
+                              const char *event_name, u64 hw_config,
                               const struct parse_events_terms *const_parsed_terms,
                               struct list_head **listp, void *loc_)
 {
 
                auto_merge_stats = perf_pmu__auto_merge_stats(pmu);
                if (!parse_events_add_pmu(parse_state, list, pmu,
-                                         &parsed_terms, auto_merge_stats)) {
+                                         &parsed_terms, auto_merge_stats, hw_config)) {
                        struct strbuf sb;
 
                        strbuf_init(&sb, /*hint=*/ 0);
 
        if (parse_state->fake_pmu) {
                if (!parse_events_add_pmu(parse_state, list, perf_pmus__fake_pmu(), &parsed_terms,
-                                         /*auto_merge_stats=*/true)) {
+                                         /*auto_merge_stats=*/true, hw_config)) {
                        struct strbuf sb;
 
                        strbuf_init(&sb, /*hint=*/ 0);
        /* Attempt to add to list assuming event_or_pmu is a PMU name. */
        pmu = perf_pmus__find(event_or_pmu);
        if (pmu && !parse_events_add_pmu(parse_state, *listp, pmu, const_parsed_terms,
-                                       /*auto_merge_stats=*/false))
+                                        /*auto_merge_stats=*/false,
+                                        /*alternate_hw_config=*/PERF_COUNT_HW_MAX))
                return 0;
 
        if (parse_state->fake_pmu) {
                if (!parse_events_add_pmu(parse_state, *listp, perf_pmus__fake_pmu(),
                                          const_parsed_terms,
-                                         /*auto_merge_stats=*/false))
+                                         /*auto_merge_stats=*/false,
+                                         /*alternate_hw_config=*/PERF_COUNT_HW_MAX))
                        return 0;
        }
 
 
                        if (!parse_events_add_pmu(parse_state, *listp, pmu,
                                                  const_parsed_terms,
-                                                 auto_merge_stats)) {
+                                                 auto_merge_stats,
+                                                 /*alternate_hw_config=*/PERF_COUNT_HW_MAX)) {
                                ok++;
                                parse_state->wild_card_pmus = true;
                        }
 
        /* Failure to add, assume event_or_pmu is an event name. */
        zfree(listp);
-       if (!parse_events_multi_pmu_add(parse_state, event_or_pmu, const_parsed_terms, listp, loc))
+       if (!parse_events_multi_pmu_add(parse_state, event_or_pmu, PERF_COUNT_HW_MAX,
+                                       const_parsed_terms, listp, loc))
                return 0;
 
        if (asprintf(&help, "Unable to find PMU or event on a PMU of '%s'", event_or_pmu) < 0)