diff --git a/docs/misc/xen-command-line.markdown b/docs/misc/xen-command-line.markdown
index 467dc8f..5ed0730 100644
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -1476,7 +1476,7 @@ Use Virtual Processor ID support if available.  This prevents the need for TLB
 flushes on VM entry and exit, increasing performance.
 
 ### vpmu
-> `= ( bts )`
+> `= ( <boolean> | { bts | ipc | arch [, ...] } )`
 
 > Default: `off`
 
@@ -1492,6 +1492,19 @@ wrong behaviour (see handle\_pmc\_quirk()).
 If 'vpmu=bts' is specified the virtualisation of the Branch Trace Store (BTS)
 feature is switched on on Intel processors supporting this feature.
 
+vpmu=ipc enables performance monitoring, but restricts the counters to the
+most minimum set possible: instructions, cycles, and reference cycles. These
+can be used to calculate instructions per cycle (IPC).
+
+vpmu=arch enables performance monitoring, but restricts the counters to the
+pre-defined architectural events only. These are exposed by cpuid, and listed
+in the Pre-Defined Architectural Performance Events table from the Intel 64
+and IA-32 Architectures Software Developer's Manual, Volume 3B, System
+Programming Guide, Part 2.
+
+If a boolean is not used, combinations of flags are allowed, comma separated.
+For example, vpmu=arch,bts.
+
 Note that if **watchdog** option is also specified vpmu will be turned off.
 
 *Warning:*
diff --git a/xen/arch/x86/cpu/vpmu.c b/xen/arch/x86/cpu/vpmu.c
index 4856e98..004f71a 100644
--- a/xen/arch/x86/cpu/vpmu.c
+++ b/xen/arch/x86/cpu/vpmu.c
@@ -43,34 +43,59 @@ CHECK_pmu_data;
 CHECK_pmu_params;
 
 /*
- * "vpmu" :     vpmu generally enabled
- * "vpmu=off" : vpmu generally disabled
- * "vpmu=bts" : vpmu enabled and Intel BTS feature switched on.
+ * "vpmu" :     vpmu generally enabled (all counters)
+ * "vpmu=off"  : vpmu generally disabled
+ * "vpmu=bts"  : vpmu enabled and Intel BTS feature switched on.
+ * "vpmu=ipc"  : vpmu enabled for IPC counters only (most restrictive)
+ * "vpmu=arch" : vpmu enabled for predef arch counters only (restrictive)
+ * flag combinations are allowed, eg, "vpmu=ipc,bts".
  */
 static unsigned int __read_mostly opt_vpmu_enabled;
 unsigned int __read_mostly vpmu_mode = XENPMU_MODE_OFF;
 unsigned int __read_mostly vpmu_features = 0;
-static void parse_vpmu_param(char *s);
-custom_param("vpmu", parse_vpmu_param);
+static void parse_vpmu_params(char *s);
+custom_param("vpmu", parse_vpmu_params);
 
 static DEFINE_SPINLOCK(vpmu_lock);
 static unsigned vpmu_count;
 
 static DEFINE_PER_CPU(struct vcpu *, last_vcpu);
 
-static void __init parse_vpmu_param(char *s)
+static int parse_vpmu_param(char *s, int len)
 {
+    if ( ! *s || ! len )
+        return 0;
+    if ( !strncmp(s, "bts", len) )
+        vpmu_features |= XENPMU_FEATURE_INTEL_BTS;
+    else if ( !strncmp(s, "ipc", len) )
+        vpmu_features |= XENPMU_FEATURE_IPC_ONLY;
+    else if ( !strncmp(s, "arch", len) )
+        vpmu_features |= XENPMU_FEATURE_ARCH_ONLY;
+    else
+        return 1;
+    return 0;
+}
+
+static void __init parse_vpmu_params(char *s)
+{
+    char *sep, *p = s;
+
     switch ( parse_bool(s) )
     {
     case 0:
         break;
     default:
-        if ( !strcmp(s, "bts") )
-            vpmu_features |= XENPMU_FEATURE_INTEL_BTS;
-        else if ( *s )
+        while (1)
         {
-            printk("VPMU: unknown flag: %s - vpmu disabled!\n", s);
-            break;
+            sep = strchr(p, ',');
+            if ( sep == NULL )
+                sep = strchr(p, 0);
+            if ( parse_vpmu_param(p, sep - p) )
+                goto error;
+            if ( *sep == 0 )
+                /* reached end of flags */
+                break;
+            p = sep + 1;
         }
         /* fall through */
     case 1:
@@ -79,6 +104,10 @@ static void __init parse_vpmu_param(char *s)
         opt_vpmu_enabled = 1;
         break;
     }
+    return;
+
+ error:
+    printk("VPMU: unknown flags: %s - vpmu disabled!\n", s);
 }
 
 void vpmu_lvtpc_update(uint32_t val)
diff --git a/xen/arch/x86/cpu/vpmu_intel.c b/xen/arch/x86/cpu/vpmu_intel.c
index 3eff1ae..4d1bae0 100644
--- a/xen/arch/x86/cpu/vpmu_intel.c
+++ b/xen/arch/x86/cpu/vpmu_intel.c
@@ -604,12 +604,17 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
                  "MSR_PERF_GLOBAL_STATUS(0x38E)!\n");
         return -EINVAL;
     case MSR_IA32_PEBS_ENABLE:
+        if ( vpmu_features & (XENPMU_FEATURE_IPC_ONLY |
+             XENPMU_FEATURE_ARCH_ONLY) )
+            return -EINVAL;
         if ( msr_content & 1 )
             gdprintk(XENLOG_WARNING, "Guest is trying to enable PEBS, "
                      "which is not supported.\n");
         core2_vpmu_cxt->pebs_enable = msr_content;
         return 0;
     case MSR_IA32_DS_AREA:
+        if ( !(vpmu_features & XENPMU_FEATURE_INTEL_BTS) )
+            return -EINVAL;
         if ( vpmu_is_set(vpmu, VPMU_CPU_HAS_DS) )
         {
             if ( !(has_hvm_container_vcpu(v)
@@ -656,12 +661,55 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
         tmp = msr - MSR_P6_EVNTSEL(0);
         if ( tmp >= 0 && tmp < arch_pmc_cnt )
         {
+            bool_t blocked = 0;
+            uint64_t umaskevent;
             struct xen_pmu_cntr_pair *xen_pmu_cntr_pair =
                 vpmu_reg_pointer(core2_vpmu_cxt, arch_counters);
 
             if ( msr_content & ARCH_CTRL_MASK )
                 return -EINVAL;
 
+            /* PMC filters */
+            umaskevent = msr_content & MSR_IA32_CMT_EVTSEL_UE_MASK;
+            if ( vpmu_features & XENPMU_FEATURE_IPC_ONLY ||
+                 vpmu_features & XENPMU_FEATURE_ARCH_ONLY )
+            {
+                blocked = 1;
+                switch ( umaskevent )
+                {
+                /*
+                 * See the Pre-Defined Architectural Performance Events table
+                 * from the Intel 64 and IA-32 Architectures Software
+                 * Developer's Manual, Volume 3B, System Programming Guide,
+                 * Part 2.
+                 */
+                case 0x003c:	/* UnHalted Core Cycles */
+                case 0x013c:	/* UnHalted Reference Cycles */
+                case 0x00c0:	/* Instructions Retired */
+                    blocked = 0;
+                default:
+                    break;
+                }
+            }
+
+            if ( vpmu_features & XENPMU_FEATURE_ARCH_ONLY )
+            {
+                /* additional counters beyond IPC only; blocked already set */
+                switch ( umaskevent )
+                {
+                case 0x4f2e:	/* Last Level Cache References */
+                case 0x412e:	/* Last Level Cache Misses */
+                case 0x00c4:	/* Branch Instructions Retired */
+                case 0x00c5:	/* All Branch Mispredict Retired */
+                    blocked = 0;
+                default:
+                    break;
+               }
+            }
+
+            if ( blocked )
+                return -EINVAL;
+
             if ( has_hvm_container_vcpu(v) )
                 vmx_read_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL,
                                    &core2_vpmu_cxt->global_ctrl);
diff --git a/xen/include/asm-x86/msr-index.h b/xen/include/asm-x86/msr-index.h
index 2b97861..84da631 100644
--- a/xen/include/asm-x86/msr-index.h
+++ b/xen/include/asm-x86/msr-index.h
@@ -329,6 +329,7 @@
 
 /* Platform Shared Resource MSRs */
 #define MSR_IA32_CMT_EVTSEL		0x00000c8d
+#define MSR_IA32_CMT_EVTSEL_UE_MASK	0x0000ffff
 #define MSR_IA32_CMT_CTR		0x00000c8e
 #define MSR_IA32_PSR_ASSOC		0x00000c8f
 #define MSR_IA32_PSR_L3_QOS_CFG	0x00000c81
diff --git a/xen/include/public/pmu.h b/xen/include/public/pmu.h
index 7753df0..0e1312c 100644
--- a/xen/include/public/pmu.h
+++ b/xen/include/public/pmu.h
@@ -84,9 +84,19 @@ DEFINE_XEN_GUEST_HANDLE(xen_pmu_params_t);
 
 /*
  * PMU features:
- * - XENPMU_FEATURE_INTEL_BTS: Intel BTS support (ignored on AMD)
+ * - XENPMU_FEATURE_INTEL_BTS:  Intel BTS support (ignored on AMD)
+ * - XENPMU_FEATURE_IPC_ONLY:   Restrict PMCs to the most minimum set possible.
+ *                              Instructions, cycles, and ref cycles. Can be
+ *                              used to calculate instructions-per-cycle (IPC)
+ *                              (ignored on AMD).
+ * - XENPMU_FEATURE_ARCH_ONLY:  Restrict PMCs to the Intel Pre-Defined
+ *                              Architectural Performance Events exposed by
+ *                              cpuid and listed in the Intel developer's manual
+ *                              (ignored on AMD).
  */
-#define XENPMU_FEATURE_INTEL_BTS  1
+#define XENPMU_FEATURE_INTEL_BTS  (1<<0)
+#define XENPMU_FEATURE_IPC_ONLY   (1<<1)
+#define XENPMU_FEATURE_ARCH_ONLY  (1<<2)
 
 /*
  * Shared PMU data between hypervisor and PV(H) domains.
