diff --git a/tools/sepolicy-analyze/Android.mk b/tools/sepolicy-analyze/Android.mk
index 3f957027b6c1075908feab56651e5f0c89ebc91b..e65efe9ee433abc07f3439886e71b505d78e1620 100644
--- a/tools/sepolicy-analyze/Android.mk
+++ b/tools/sepolicy-analyze/Android.mk
@@ -7,7 +7,7 @@ LOCAL_MODULE := sepolicy-analyze
 LOCAL_MODULE_TAGS := optional
 LOCAL_C_INCLUDES := external/libsepol/include
 LOCAL_CFLAGS := -Wall -Werror
-LOCAL_SRC_FILES := sepolicy-analyze.c dups.c neverallow.c perm.c typecmp.c booleans.c utils.c
+LOCAL_SRC_FILES := sepolicy-analyze.c dups.c neverallow.c perm.c typecmp.c booleans.c attribute.c utils.c
 LOCAL_STATIC_LIBRARIES := libsepol
 
 include $(BUILD_HOST_EXECUTABLE)
diff --git a/tools/sepolicy-analyze/README b/tools/sepolicy-analyze/README
index 0cb890b6d6d605fb1bfc956663ef0221f2690379..d18609a7c45bc93d73ed728682957557e7002e85 100644
--- a/tools/sepolicy-analyze/README
+++ b/tools/sepolicy-analyze/README
@@ -60,6 +60,11 @@ sepolicy-analyze
     Policy booleans are forbidden in Android policy, so if there is any
     output, the policy will fail CTS.
 
+    ATTRIBUTE (attribute)
+    sepolicy-analyze out/target/product/<board>/root/sepolicy attribute <name>
+
+    Displays the types associated with the specified attribute name.
+
     NEVERALLOW CHECKING (neverallow)
     sepolicy-analyze out/target/product/<board>/root/sepolicy neverallow \
     [-w] [-d] [-f neverallows.conf] | [-n "neverallow string"]
diff --git a/tools/sepolicy-analyze/attribute.c b/tools/sepolicy-analyze/attribute.c
new file mode 100644
index 0000000000000000000000000000000000000000..474bda2fdbb43bdaf86ebe7293538845d0401187
--- /dev/null
+++ b/tools/sepolicy-analyze/attribute.c
@@ -0,0 +1,39 @@
+#include "attribute.h"
+
+void attribute_usage() {
+    fprintf(stderr, "\tattribute <attribute-name>\n");
+}
+
+static int list_attribute(policydb_t * policydb, char *name)
+{
+    struct type_datum *attr;
+    struct ebitmap_node *n;
+    unsigned int bit;
+
+    attr = hashtab_search(policydb->p_types.table, name);
+    if (!attr) {
+        fprintf(stderr, "%s is not defined in this policy.\n", name);
+        return -1;
+    }
+
+    if (attr->flavor != TYPE_ATTRIB) {
+        fprintf(stderr, "%s is a type not an attribute in this policy.\n", name);
+        return -1;
+    }
+
+    ebitmap_for_each_bit(&policydb->attr_type_map[attr->s.value - 1], n, bit) {
+        if (!ebitmap_node_get_bit(n, bit))
+            continue;
+        printf("%s\n", policydb->p_type_val_to_name[bit]);
+    }
+
+    return 0;
+}
+
+int attribute_func (int argc, char **argv, policydb_t *policydb) {
+    if (argc != 2) {
+        USAGE_ERROR = true;
+        return -1;
+    }
+    return list_attribute(policydb, argv[1]);
+}
diff --git a/tools/sepolicy-analyze/attribute.h b/tools/sepolicy-analyze/attribute.h
new file mode 100644
index 0000000000000000000000000000000000000000..05adcbd90a48de45008c782a4686740bf2851cd2
--- /dev/null
+++ b/tools/sepolicy-analyze/attribute.h
@@ -0,0 +1,11 @@
+#ifndef ATTRIBUTE_H
+#define ATTRIBUTE_H
+
+#include <sepol/policydb/policydb.h>
+
+#include "utils.h"
+
+void attribute_usage(void);
+int attribute_func(int argc, char **argv, policydb_t *policydb);
+
+#endif /* ATTRIBUTE_H */
diff --git a/tools/sepolicy-analyze/sepolicy-analyze.c b/tools/sepolicy-analyze/sepolicy-analyze.c
index a6fa20052b05971fe76c87eda65316ea8ac80df6..b70eaaa0a054555b5a126be2ef43498e48dc16d7 100644
--- a/tools/sepolicy-analyze/sepolicy-analyze.c
+++ b/tools/sepolicy-analyze/sepolicy-analyze.c
@@ -7,6 +7,7 @@
 #include "perm.h"
 #include "typecmp.h"
 #include "booleans.h"
+#include "attribute.h"
 #include "utils.h"
 
 #define NUM_COMPONENTS (int) (sizeof(analyze_components)/sizeof(analyze_components[0]))
@@ -22,7 +23,8 @@ static struct {
     COMP(neverallow),
     COMP(permissive),
     COMP(typecmp),
-    COMP(booleans)
+    COMP(booleans),
+    COMP(attribute)
 };
 
 void usage(char *arg0)