diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index 5607eb01b7b9dd9b37d33d5d84c496fc614cd99f..e49a7996a9fd930fdafa42142bf2742e4365fea5 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -261,6 +261,17 @@
 					completely disabled)</para>
 				<para>	<literal>voice</literal>	Voice mode (returns from FAX mode, reverting the changes that were made)</para>
 			</enum>
+			<enum name="dialmode">
+				<para>R/W Pulse and tone dialing mode of the channel.</para>
+				<para>If set, overrides the setting in <literal>chan_dahdi.conf</literal> for that channel.</para>
+				<enumlist>
+					<enum name="both" />
+					<enum name="pulse" />
+					<enum name="dtmf" />
+					<enum name="tone" />
+					<enum name="none" />
+				</enumlist>
+			</enum>
 		</enumlist>
 	</info>
 	<info name="Dial_Resource" language="en_US" tech="DAHDI">
@@ -1034,6 +1045,7 @@ static struct dahdi_chan_conf dahdi_chan_conf_default(void)
 			.mohsuggest = "",
 			.parkinglot = "",
 			.transfertobusy = 1,
+			.dialmode = 0,
 
 			.ani_info_digits = 2,
 			.ani_wink_time = 1000,
@@ -7009,6 +7021,32 @@ static int dahdi_func_read(struct ast_channel *chan, const char *function, char
 		}
 		ast_mutex_unlock(&p->lock);
 #endif	/* defined(HAVE_PRI) */
+	} else if (!strcasecmp(data, "dialmode")) {
+		struct analog_pvt *analog_p;
+		ast_mutex_lock(&p->lock);
+		analog_p = p->sig_pvt;
+		/* Hardcode p->radio and p->oprmode as 0 since we're using this to check for analogness, not the handler */
+		if (dahdi_analog_lib_handles(p->sig, 0, 0) && analog_p) {
+			switch (analog_p->dialmode) {
+			case ANALOG_DIALMODE_BOTH:
+				ast_copy_string(buf, "both", len);
+				break;
+			case ANALOG_DIALMODE_PULSE:
+				ast_copy_string(buf, "pulse", len);
+				break;
+			case ANALOG_DIALMODE_DTMF:
+				ast_copy_string(buf, "dtmf", len);
+				break;
+			case ANALOG_DIALMODE_NONE:
+				ast_copy_string(buf, "none", len);
+				break;
+			}
+		} else {
+			ast_log(LOG_WARNING, "%s only supported on analog channels\n", data);
+			*buf = '\0';
+			res = -1;
+		}
+		ast_mutex_unlock(&p->lock);
 	} else {
 		*buf = '\0';
 		res = -1;
@@ -7114,6 +7152,30 @@ static int dahdi_func_write(struct ast_channel *chan, const char *function, char
 			ast_log(LOG_WARNING, "Unsupported value '%s' provided for '%s' item.\n", value, data);
 			res = -1;
 		}
+	} else if (!strcasecmp(data, "dialmode")) {
+		struct analog_pvt *analog_p;
+
+		ast_mutex_lock(&p->lock);
+		analog_p = p->sig_pvt;
+		if (!dahdi_analog_lib_handles(p->sig, 0, 0) || !analog_p) {
+			ast_log(LOG_WARNING, "%s only supported on analog channels\n", data);
+			ast_mutex_unlock(&p->lock);
+			return -1;
+		}
+		/* analog pvt is used for pulse dialing, so update both */
+		if (!strcasecmp(value, "pulse")) {
+			p->dialmode = analog_p->dialmode = ANALOG_DIALMODE_PULSE;
+		} else if (!strcasecmp(value, "dtmf") || !strcasecmp(value, "tone")) {
+			p->dialmode = analog_p->dialmode = ANALOG_DIALMODE_DTMF;
+		} else if (!strcasecmp(value, "none")) {
+			p->dialmode = analog_p->dialmode = ANALOG_DIALMODE_NONE;
+		} else if (!strcasecmp(value, "both")) {
+			p->dialmode = analog_p->dialmode = ANALOG_DIALMODE_BOTH;
+		} else {
+			ast_log(LOG_WARNING, "'%s' is an invalid setting for %s\n", value, data);
+			res = -1;
+		}
+		ast_mutex_unlock(&p->lock);
 	} else {
 		res = -1;
 	}
@@ -8997,6 +9059,13 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
 			} else {
 				dahdi_handle_dtmf(ast, idx, &f);
 			}
+			if (!(p->dialmode == ANALOG_DIALMODE_BOTH || p->dialmode == ANALOG_DIALMODE_DTMF)) {
+				if (f->frametype == AST_FRAME_DTMF_END) { /* only show this message when the key is let go of */
+					ast_debug(1, "Dropping DTMF digit '%c' because tone dialing is disabled\n", f->subclass.integer);
+				}
+				f->frametype = AST_FRAME_NULL;
+				f->subclass.integer = 0;
+			}
 			break;
 		case AST_FRAME_VOICE:
 			if (p->cidspill || p->cid_suppress_expire) {
@@ -12780,6 +12849,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 #endif
 		tmp->immediate = conf->chan.immediate;
 		tmp->transfertobusy = conf->chan.transfertobusy;
+		tmp->dialmode = conf->chan.dialmode;
 		if (chan_sig & __DAHDI_SIG_FXS) {
 			tmp->mwimonitor_fsk = conf->chan.mwimonitor_fsk;
 			tmp->mwimonitor_neon = conf->chan.mwimonitor_neon;
@@ -13113,6 +13183,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
 				analog_p->threewaycalling = conf->chan.threewaycalling;
 				analog_p->transfer = conf->chan.transfer;
 				analog_p->transfertobusy = conf->chan.transfertobusy;
+				analog_p->dialmode = conf->chan.dialmode;
 				analog_p->use_callerid = tmp->use_callerid;
 				analog_p->usedistinctiveringdetection = tmp->usedistinctiveringdetection;
 				analog_p->use_smdi = tmp->use_smdi;
@@ -18314,6 +18385,16 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
 			confp->chan.immediate = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "transfertobusy")) {
 			confp->chan.transfertobusy = ast_true(v->value);
+		} else if (!strcasecmp(v->name, "dialmode")) {
+			if (!strcasecmp(v->value, "pulse")) {
+				confp->chan.dialmode = ANALOG_DIALMODE_PULSE;
+			} else if (!strcasecmp(v->value, "dtmf") || !strcasecmp(v->value, "tone")) {
+				confp->chan.dialmode = ANALOG_DIALMODE_DTMF;
+			} else if (!strcasecmp(v->value, "none")) {
+				confp->chan.dialmode = ANALOG_DIALMODE_NONE;
+			} else {
+				confp->chan.dialmode = ANALOG_DIALMODE_BOTH;
+			}
 		} else if (!strcasecmp(v->name, "mwimonitor")) {
 			confp->chan.mwimonitor_neon = 0;
 			confp->chan.mwimonitor_fsk = 0;
diff --git a/channels/chan_dahdi.h b/channels/chan_dahdi.h
index de813f21bf653ae56fda64cc7afc0e75c3209327..8f1668752806c54d9f7f59e60cbf6c8938f404b6 100644
--- a/channels/chan_dahdi.h
+++ b/channels/chan_dahdi.h
@@ -146,6 +146,7 @@ struct dahdi_pvt {
 	 * \note Set to a couple of nonzero values but it is only tested like a boolean.
 	 */
 	int radio;
+	int dialmode;					/*!< Dialing Modes Allowed (Pulse/Tone) */
 	int outsigmod;					/*!< Outbound Signalling style (modifier) */
 	int oprmode;					/*!< "Operator Services" mode */
 	struct dahdi_pvt *oprpeer;				/*!< "Operator Services" peer tech_pvt ptr */
diff --git a/channels/sig_analog.c b/channels/sig_analog.c
index b694a96082378a9e975cdee8036d8b9c64bf9870..5ae96d9418d2598acde993ae713ca23bebd88350 100644
--- a/channels/sig_analog.c
+++ b/channels/sig_analog.c
@@ -2775,9 +2775,13 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
 		analog_set_pulsedial(p, (res & ANALOG_EVENT_PULSEDIGIT) ? 1 : 0);
 		ast_debug(1, "Detected %sdigit '%c'\n", (res & ANALOG_EVENT_PULSEDIGIT) ? "pulse ": "", res & 0xff);
 		analog_confmute(p, 0);
-		p->subs[idx].f.frametype = AST_FRAME_DTMF_END;
-		p->subs[idx].f.subclass.integer = res & 0xff;
-		analog_handle_dtmf(p, ast, idx, &f);
+		if (p->dialmode == ANALOG_DIALMODE_BOTH || p->dialmode == ANALOG_DIALMODE_PULSE) {
+			p->subs[idx].f.frametype = AST_FRAME_DTMF_END;
+			p->subs[idx].f.subclass.integer = res & 0xff;
+			analog_handle_dtmf(p, ast, idx, &f);
+		} else {
+			ast_debug(1, "Dropping pulse digit '%c' because pulse dialing disabled on channel %d\n", res & 0xff, p->channel);
+		}
 		return f;
 	}
 
diff --git a/channels/sig_analog.h b/channels/sig_analog.h
index 7e9acda55cac35c5ed5819d5c10b4b08c98a17ef..07e1cdd2aa1a7613c05074c8e495993b79891491 100644
--- a/channels/sig_analog.h
+++ b/channels/sig_analog.h
@@ -116,6 +116,13 @@ enum analog_dsp_digitmode {
 	ANALOG_DIGITMODE_MF,
 };
 
+enum analog_dialmode {
+	ANALOG_DIALMODE_BOTH = 0,
+	ANALOG_DIALMODE_PULSE,
+	ANALOG_DIALMODE_DTMF,
+	ANALOG_DIALMODE_NONE,
+};
+
 enum analog_cid_start {
 	ANALOG_CID_START_POLARITY = 1,
 	ANALOG_CID_START_POLARITY_IN,
@@ -308,6 +315,7 @@ struct analog_pvt {
 	int channel;					/*!< Channel Number */
 
 	enum analog_sigtype outsigmod;
+	enum analog_dialmode dialmode;	/*!< Which of pulse and/or tone dialing to support */
 	int echotraining;
 	int cid_signalling;				/*!< Asterisk callerid type we're using */
 	int polarityonanswerdelay;
diff --git a/configs/samples/chan_dahdi.conf.sample b/configs/samples/chan_dahdi.conf.sample
index 6b2954975091b4eca90aaf47fbb9d4d484f7ee89..c54f482566715b4560e9e013bec08774ab1f75bc 100644
--- a/configs/samples/chan_dahdi.conf.sample
+++ b/configs/samples/chan_dahdi.conf.sample
@@ -1131,10 +1131,19 @@ pickupgroup=1
 ;
 ; For FXO (FXS signalled) devices, whether to use pulse dial instead of DTMF
 ; Pulse digits from phones (FXS devices, FXO signalling) are always
-; detected.
+; detected, unless the dialmode setting has been changed from the default.
 ;
 ;pulsedial=yes
 ;
+; For FXS (FXO signalled) devices, the dialing modes to support for the channel.
+; By default, both pulse and tone (DTMF) dialing are always detected.
+; May be set to "pulse" if you only want to allow pulse dialing on a line.
+; May be set to "dtmf" or "tone" to only allow tone dialing on a line.
+; May be set to "none" to prevent dialing entirely.
+; You can also change this during a call using the CHANNEL function in the dialplan.
+;
+;dialmode=both
+;
 ; For fax detection, uncomment one of the following lines.  The default is *OFF*
 ;
 ;faxdetect=both